/*
 * Copyright (C) 2011  Paulo Cesar Pereira de Andrade.
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * Authors:
 *	Paulo Cesar Pereira de Andrade
 */

/* This macro adds a huge overhead to jit generation code, and
 * is handled somewhat like GC_DEBUG, that is, only enabled from
 * time to time, to brute force test problems.
 * FIXME Add more related macros for runtime assertions and
 * have a specific define key to enable it.
 * */
#define JIT_DEBUG	0

/* FIXME rework should be done for eop_ld and eop_lc with dynamically
 * typed objects to allow/handle null as small integers and also allow
 * null as a valid float. Should basically add a null check and jump
 * to fallback.
 */

#if PROTO
#  define lint		0x00010000
#  define lrel		0x00020000
#  define li32		0x00040000
#  define lu32		0x00080000
#  define li64		0x00100000
#  define lu64		0x00200000
#  define lf32		0x00400000
#  define lf64		0x00800000
#  define rint		0x00000100
#  define rrel		0x00000200
#  define ri32		0x00000400
#  define ru32		0x00000800
#  define ri64		0x00001000
#  define ru64		0x00002000
#  define rf32		0x00004000
#  define rf64		0x00008000
#  define iint		0x00000001
#  define irel		0x00000002
#  define ii32		0x00000004
#  define iu32		0x00000008
#  define ii64		0x00000010
#  define iu64		0x00000020
#  define if32		0x00000040
#  define if64		0x00000080

#  define load_stack()							\
    jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, esp))
#  define pop_stack()							\
    jit_subi(JIT_R1, JIT_R1, sizeof(evalue_t));				\
    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_R1)

static void
emit_int_implicit(east_list_t *ast0, ebool_t type);

static void
emit_int(east_list_t *ast0);

static void
emit_float(east_list_t *ast0);

static void
emit_load_incdec(east_list_t *ast0, east_list_t *ast1);

static void
emit_load_push(east_list_t *ast0, east_list_t *ast1);

static void
emit_load_push_int_cmp(east_list_t *ast0, east_list_t *ast1,
		       east_list_t *ast2, east_list_t *ast3);

static void
emit_load_push_int_cmp_jmp(east_list_t *ast0, east_list_t *ast1,
			   east_list_t *ast2, east_list_t *ast3,
			   east_list_t *ast4);

static void
emit_load_push_int_addsub(east_list_t *ast0, east_list_t *ast1,
			  east_list_t *ast2, east_list_t *ast3);

static void
emit_load_push_float_cmp(east_list_t *ast0, east_list_t *ast1,
			 east_list_t *ast2, east_list_t *ast3);

static void
emit_load_push_float_cmp_jmp(east_list_t *ast0, east_list_t *ast1,
			     east_list_t *ast2, east_list_t *ast3,
			     east_list_t *ast4);

static void
emit_load_push_load_cmp(east_list_t *ast0, east_list_t *ast1,
			east_list_t *ast2, east_list_t *ast3);

static void
emit_load_push_load_cmp_jmp(east_list_t *ast0, east_list_t *ast1,
			    east_list_t *ast2, east_list_t *ast3,
			    east_list_t *ast4);

static void
emit_load_push_load_addsub(east_list_t *ast0, east_list_t *ast1,
			   east_list_t *ast2, east_list_t *ast3);

static void
emit_lr(east_list_t *ast0);

static void
emit_store_stack(east_list_t *ast0, eint32_t offset);

static void
emit_store_type(east_list_t *ast0, eint32_t offset, eint32_t type);

static void
emit_sdt(east_list_t *ast0);

static void
emit_sb(east_list_t *ast0);

static void
emit_sbt(east_list_t *ast0);

static void
emit_sr(east_list_t *ast0);

static void
emit_sc(east_list_t *ast0);

static void
emit_ss(east_list_t *ast0);

static void
emit_sst(east_list_t *ast0);

static void
emit_push(east_list_t *ast0);

static void
emit_pusht(east_list_t *ast0);

static void
emit_cmp(east_list_t *ast0);

static void
emit_cmp_jmp(east_list_t *ast0, east_list_t *ast1);

static void
emit_addsub(east_list_t *ast0);

static void
emit_andorxor(east_list_t *ast0);

static void
emit_boolean(east_list_t *ast0);

static void
emit_load_jmp(east_list_t *ast0, east_list_t *ast1);
#endif

#if CODE
#  if JIT_DEBUG
#    define DEBUG_IMPLICIT_TYPE()					\
	do {								\
	    jit_node_t		*_done;					\
	    jit_node_t		*_testi;				\
	    jit_node_t		*_testf;				\
	    jit_ldxi_i(JIT_R0, JIT_V0,					\
		       offsetof(ethread_t, r0) + offsetof(evalue_t, t));\
	    _testi = jit_beqi(JIT_R0, t_int);				\
	    _testf = jit_beqi(JIT_R0, t_float);				\
	    _done = jit_jmpi();						\
	    jit_patch(_testi);						\
	    jit_patch(_testf);						\
	    jit_calli(evm_abort);					\
	    jit_patch(_done);						\
	} while (0)
#    define DEBUG_IMPLICIT_TYPE_INT()					\
	do {								\
	    jit_node_t		*_done;					\
	    jit_ldxi_i(JIT_R0, JIT_V0,					\
		       offsetof(ethread_t, r0) + offsetof(evalue_t, t));\
	    _done = jit_bnei(JIT_R0, t_int);				\
	    jit_calli(evm_abort);					\
	    jit_patch(_done);						\
	} while (0)
#    define DEBUG_IMPLICIT_TYPE_FLOAT()					\
	do {								\
	    jit_node_t		*_done;					\
	    jit_ldxi_i(JIT_R0, JIT_V0,					\
		       offsetof(ethread_t, r0) + offsetof(evalue_t, t));\
	    _done = jit_bnei(JIT_R0, t_float);				\
	    jit_calli(evm_abort);					\
	    jit_patch(_done);						\
	} while (0)
#    define DEBUG_IMPLICIT_TYPE_NULL_MPR()				\
	do {								\
	    jit_node_t		*_done;					\
	    jit_node_t		*_testi;				\
	    jit_node_t		*_testf;				\
	    jit_node_t		*_testR;				\
	    jit_node_t		*_testS;				\
	    jit_node_t		*_testG;				\
	    jit_node_t		*_testn;				\
	    jit_ldxi_i(JIT_R0, JIT_V0,					\
		       offsetof(ethread_t, r0) + offsetof(evalue_t, t));\
	    _testi = jit_beqi(JIT_R0, t_int);				\
	    _testf = jit_beqi(JIT_R0, t_float);				\
	    _testR = jit_beqi(JIT_R0, t_mpr);				\
	    _testS = jit_beqi(JIT_R0, t_shr);				\
	    _testG = jit_beqi(JIT_R0, t_rgr);				\
	    _testn = jit_beqi(JIT_R0, t_void);				\
	    _done = jit_jmpi();						\
	    jit_patch(_testi);						\
	    jit_patch(_testf);						\
	    jit_patch(_testR);						\
	    jit_patch(_testS);						\
	    jit_patch(_testG);						\
	    jit_patch(_testn);						\
	    jit_calli(evm_abort);					\
	    jit_patch(_done);						\
	} while (0)
#  else
#    define DEBUG_IMPLICIT_TYPE()		/**/
#    define DEBUG_IMPLICIT_TYPE_INT()		/**/
#    define DEBUG_IMPLICIT_TYPE_FLOAT()		/**/
#    define DEBUG_IMPLICIT_TYPE_NULL_MPR()	/**/
#  endif

static void
emit_int_implicit(east_list_t *ast0, ebool_t type)
{
    edata_t		data;

    if (type) {
	jit_movi(JIT_R0, t_int);
	jit_stxi_i(offsetof(ethread_t, r0) + offsetof(evalue_t, t),
		   JIT_V0, JIT_R0);
    }
    data.L = immediate_int(east_node(ast0));
#  if __WORDSIZE == 32
    jit_movi(JIT_R0, data.s.l);
    jit_stxi(offsetof(ethread_t, r0) +
	     offsetof(evalue_t, v.i) + offsetof(edata_t, s.l),
	     JIT_V0, JIT_R0);
    if (data.s.l != data.s.h) {
	jit_movi(JIT_R2, data.s.h);
	jit_stxi(offsetof(ethread_t, r0) +
		 offsetof(evalue_t, v.i) + offsetof(edata_t, s.h),
		 JIT_V0, JIT_R2);
    }
    else
	jit_stxi(offsetof(ethread_t, r0) +
		 offsetof(evalue_t, v.i) + offsetof(edata_t, s.h),
		 JIT_V0, JIT_R0);
#else
    jit_movi(JIT_R0, data.L);
    jit_stxi(offsetof(ethread_t, r0) + offsetof(evalue_t, v.i), JIT_V0, JIT_R0);
#endif
}

static void
emit_int(east_list_t *ast0)
{
    edata_t		 data;

    data.L = immediate_int(east_node(ast0));
    if (east_node(ast0)->code == eop_int) {
	jit_movi(JIT_V1, data.s.l);
	ejit_sync = ejit_sync_register;
    }
    else {
#if __WORDSIZE == 32
	jit_movi(JIT_V1, data.s.l);
	jit_movi(JIT_V2, data.s.h);
#else
	jit_movi(JIT_V1, data.L);
#endif
	ejit_sync = ejit_sync_register|ejit_sync_int_ext;
    }
    ejit_type = ast0->itype;
}

static void
emit_float(east_list_t *ast0)
{
    edata_t		data;

    data.F = immediate_float(east_node(ast0));
    jit_movi_d(JIT_F0, data.F);
    ejit_sync = ejit_sync_register;
    ejit_type = t_float;
}

static void
emit_load(east_list_t *ast0)
{
    jit_node_t		*jump;
    jit_node_t		*next;
    jit_node_t		*done;
    jit_node_t		*fail;
    eint32_t		 kind;
    eint32_t		 soff;
    eint32_t		 toff;
    eint32_t		 voff;

    done = next = fail = null;
    switch (ast0->itype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:	case t_uint32:
	    kind = ii32;		break;
	case t_int:
	    kind = ii64;		break;
	case t_uint:
	    kind = iu64;		break;
	case t_float32:
	    kind = if32;		break;
	case t_float:
	    kind = if64;		break;
	case t_exact:
	    kind = iint;		break;
	case t_inexact:
	    kind = irel;		break;
	case t_dynamic:
	    kind = iint|irel;		break;
	default:
	    kind = 0;			break;
    }
    if (east_node(ast0)->code == eop_ls)
	soff = east_node(ast0)->cstack.offset;
    else
	soff = east_node(ast0)->csymbol.symbol->offset;
    switch (east_node(ast0)->code) {
	case eop_ld:	case eop_ldt:
	    if (kind)
		jit_ldi(JIT_R1, (jit_word_t)
			(eint8_t *)eds + soff * sizeof(eobject_t));
	    toff = -4;
	    voff = 0;
	    break;
	case eop_lb:	case eop_lbt:
	    if (kind)
		jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
	    toff = soff * sizeof(evalue_t) + offsetof(evalue_t, t);
	    voff = soff * sizeof(evalue_t) + offsetof(evalue_t, v.o);
	    break;
	case eop_lc:
	    if (kind) {
		jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
		/* pointer to 'this' */
		jit_ldxi(JIT_R1, JIT_R1,
			 -2 * sizeof(evalue_t) + offsetof(evalue_t, v.o));
	    }
	    toff = -4;
	    voff = soff;
	    break;
	case eop_ls:
	    if (kind)
		jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, esp));
	    toff = soff * sizeof(evalue_t) + offsetof(evalue_t, t);
	    voff = soff * sizeof(evalue_t) + offsetof(evalue_t, v.o);
	    break;
	default:
	    abort();
    }
    switch (kind) {
	case ii32:	case ii64:	case iu64:
	    switch (east_node(ast0)->code) {
		case eop_ld:	case eop_lb:	case eop_ls:
		    load_ireg(JIT_R1, voff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(JIT_R1, voff, ast0->itype);
		    break;
		default:
		    abort();
	    }
	    ejit_sync = ejit_sync_register;
	    break;
	case if32:	case if64:
	    switch (east_node(ast0)->code) {
		case eop_ld:	case eop_lb:	case eop_ls:
		    load_freg(JIT_R1, voff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_freg_type(JIT_R1, voff, ast0->itype);
		    break;
		default:
		    abort();
	    }
	    ejit_sync = ejit_sync_register;
	    break;
	default:
	    if (kind) {
		done = jit_forward();
		switch (east_node(ast0)->code) {
		    case eop_lb:		case eop_ls:
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			break;
		    case eop_ld:
			fail = jit_beqi(JIT_R1, 0);
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			break;
		    case eop_lc:
			jit_ldxi(JIT_R1, JIT_R1, voff);
			/* if null
			 * no need to call evm_lc but generate smaller
			 * code as loading null should be uncommon */
			fail = jit_beqi(JIT_R1, 0);
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			voff = 0;
			break;
		    default:
			abort();
		}
	    }
	    if (kind & iint) {
		next = jit_bnei(JIT_R0, t_int);
		load_ireg(JIT_R1, voff);
		store_ireg_implicit(true);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (kind & irel) {
		if (next)
		    jit_patch(next);
		next = jit_bnei(JIT_R0, t_float);
		load_freg(JIT_R1, voff);
		store_freg_implicit(true);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (next)
		jit_patch(next);
	    if (fail)
		jit_patch(fail);
	    switch (east_node(ast0)->code) {
		case eop_ld:
		    call_vi(evm_ld, soff);
		    break;
		case eop_lb:
		    call_vi(evm_lb, soff);
		    break;
		case eop_lc:
		    call_vii(evm_lc, soff, ast0->itype);
		    break;
		case eop_ls:
		    call_vi(evm_ls, soff);
		    break;
		default:
		    abort();
	    }
	    DEBUG_IMPLICIT_TYPE();
	    if (done)
		jit_link(done);
	    ejit_sync = ejit_sync_register|ejit_sync_dynamic|ejit_sync_implicit;
	    break;
    }
    ejit_type = ast0->itype;
}

static void
emit_load_incdec(east_list_t *ast0, east_list_t *ast1)
{
    jit_node_t		*done;
    jit_node_t		*fail;
    jit_node_t		*jump;
    jit_node_t		*next;
    jit_node_t		*over;
#  if __WORDSIZE == 32
    jit_node_t		*temp;
#  endif
    ecode_t		 code;
    eint32_t		 kind;
    eint32_t		 soff;
    eint32_t		 toff;
    eint32_t		 voff;
    etype_t		 type;
    ebool_t		 cdyn;
    ebool_t		 doint;
    ebool_t		 doflt;

    cdyn = false;
    done = fail = next = over = null;
    if (ast0) {
	kind = ast0->itype;
	soff = east_node(ast0)->csymbol.symbol->offset;
	type = east_node(ast0)->csymbol.symbol->type;
	switch (code = east_node(ast0)->code) {
	    case eop_ld:	case eop_ldt:
		toff = -4;	voff = 0;
		break;
	    case eop_lb:	case eop_lbt:
		toff = soff * sizeof(evalue_t) + offsetof(evalue_t, t);
		voff = soff * sizeof(evalue_t) + offsetof(evalue_t, v.o);
		break;
	    case eop_lc:
		cdyn = type == t_void || type > elast_basic_type;
		toff = -4;	voff = soff;
		break;
	    default:
		abort();
	}
    }
    else {
	soff = 0;
	code = eop_noop;
	kind = type = ast1->rtype;
	toff = offsetof(ethread_t, r0) + offsetof(evalue_t, t);
	voff = offsetof(ethread_t, r0) + offsetof(evalue_t, v.o);
    }
    switch (kind) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    kind = ri32;		break;
	case t_uint32:	case t_int:
	    kind = ri64;		break;
	case t_uint:
	    kind = ru64;		break;
	case t_float32:
	    kind = rf32;		break;
	case t_float64:
	    kind = rf64;		break;
	case t_exact:
	    kind = rint;		break;
	case t_inexact:
	    kind = rrel;		break;
	case t_dynamic:
	    kind = rint|rrel;		break;
	default:
	    kind = 0;			break;
    }
    switch (ast1->itype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    kind |= ii32;		break;
	case t_uint32:	case t_int:
	    kind |= ii64;		break;
	case t_uint:	case t_exact:
	    kind |= iint;		break;
	case t_float64:
	    kind |= if64;		break;
	case t_inexact:
	    kind |= irel;		break;
	case t_dynamic:
	    kind |= iint|irel;		break;
	default:			break;
    }
    doint = !!(kind & (ri32|ri64|ru64|rint));
    doflt = !!(kind & (rf32|rf64|rrel));
    if (doint || doflt) {
	switch (code) {
	    case eop_noop:
		break;
	    case eop_ld:	case eop_ldt:
		jit_ldi(JIT_R1, (jit_word_t)
			(eint8_t *)eds + soff * sizeof(eobject_t));
		break;
	    case eop_lb:	case eop_lbt:
		jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
		break;
	    case eop_lc:
		jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
		/* pointer to 'this' */
		jit_ldxi(JIT_R1, JIT_R1,
			 -2 * sizeof(evalue_t) + offsetof(evalue_t, v.o));
		if (cdyn) {
		    jit_ldxi(JIT_R1, JIT_R1, soff);
		    voff = 0;
		}
		break;
	    default:
		abort();
	}
    }
    switch (kind) {
	case ri32|ii32:
	    switch (code) {
		case eop_noop:
		    maybe_reload_ireg32_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg_type(JIT_R1, voff, ast0->itype);
		    load_ireg(JIT_R1, voff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(JIT_R1, voff, ast0->itype);
		    break;
		default:
		    abort();
	    }
	    if (east_node(ast1)->code == eop_inc)
		jit_addi(JIT_V1, JIT_V1, 1);
	    else
		jit_subi(JIT_V1, JIT_V1, 1);
	    ejit_sync = ejit_sync_register;
	    break;
	case ri32|ii64:		case ri64|ii64:
	    switch (code) {
		case eop_noop:
		    maybe_reload_extend_ireg_implicit(type);
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg(JIT_R1, voff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(JIT_R1, voff, type);
		    zero_sign_extend(type);
		    break;
		default:
		    abort();
	    }
#  if __WORDSIZE == 32
	    if (east_node(ast1)->code == eop_inc) {
		done = jit_bxaddi_u(JIT_V1, 1);
		jit_addi(JIT_V2, JIT_V2, 1);
	    }
	    else {
		done = jit_bxsubi_u(JIT_V1, 1);
		jit_subi(JIT_V2, JIT_V2, 1);
	    }
	    jit_patch(done);
#  else
	    if (east_node(ast1)->code == eop_inc)
		jit_addi(JIT_V1, JIT_V1, 1);
	    else
		jit_subi(JIT_V1, JIT_V1, 1);
#  endif
	    ejit_sync = ejit_sync_register|ejit_sync_int_ext;
	    break;
	case ri64|iint:		case ru64|iint:
	    done = jit_forward();
	    over = jit_forward();
	    switch (code) {
		case eop_noop:
		    if (!(ejit_sync & ejit_sync_implicit)) {
			assert(ejit_sync & ejit_sync_register);
			/* if cannot reload value */
			store_ireg_implicit(true);
		    }
		    else
			maybe_reload_extend_ireg_implicit(type);
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg(JIT_R1, voff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(JIT_R1, voff, ast0->itype);
		    zero_sign_extend(ast0->itype);
		    break;
		default:
		    abort();
	    }
#  if __WORDSIZE == 32
	    temp = null;
	    if (east_node(ast1)->code == eop_inc) {
		if (kind & ru64) {
		    jit_addci(JIT_V1, JIT_V1, 1);
		    jit_addxi(JIT_V2, JIT_V2, 0);
		    jump = jit_blti(JIT_V2, 0);
		}
		else {
		    temp = jit_bxaddi_u(JIT_V1, 1);
		    jump = jit_boaddi(JIT_V2, 1);
		}
	    }
	    else {
		if (kind & ru64) {
		    jit_subci(JIT_V1, JIT_V1, 1);
		    jit_subxi(JIT_V2, JIT_V2, 0);
		    jump = jit_blti(JIT_V2, 0);
		}
		else {
		    temp = jit_bxsubi_u(JIT_V1, 1);
		    jump = jit_bosubi(JIT_V2, 1);
		}
	    }
	    if (temp)
		jit_patch(temp);
#  else
	    if (east_node(ast1)->code == eop_inc) {
		if (kind & ru64) {
		    jit_addi(JIT_V1, JIT_V1, 1);
		    jump = jit_blti(JIT_V1, 0);
		}
		else
		    jump = jit_boaddi(JIT_V1, 1);
	    }
	    else {
		if (kind & ru64) {
		    jit_subi(JIT_V1, JIT_V1, 1);
		    jump = jit_blti(JIT_V1, 0);
		}
		else
		    jump = jit_bosubi(JIT_V1, 1);
	    }
#  endif
	    jit_patch_at(jump, over);
	    store_ireg_implicit(code != eop_noop);
	    jump = jit_jmpi();
	    jit_patch_at(jump, done);
	    goto overflow;
	case rf32|if64:
	    if (code == eop_noop) {
		if (!(ejit_sync & ejit_sync_register))
		    load_freg_implicit();
		else if (!(ejit_sync_float_ext))
		    jit_extr_f_d(JIT_F0, JIT_F1);
	    }
	    else {
		load_freg_type(JIT_R1, voff, t_float32);
		jit_extr_f_d(JIT_F0, JIT_F1);
	    }
	    goto incdec_float;
	case rf64|if64:
	    if (code == eop_noop)
		maybe_reload_freg_implicit();
	    else
		load_freg(JIT_R1, voff);
	incdec_float:
	    if (east_node(ast1)->code == eop_inc)
		jit_addi_d(JIT_F0, JIT_F0, 1.0);
	    else
		jit_subi_d(JIT_F0, JIT_F0, 1.0);
	    ejit_sync = ejit_sync_register;
	    break;
	default:
	    if (doint || doflt) {
		done = jit_forward();
		switch (code) {
		    case eop_noop:
			assert(ejit_sync & ejit_sync_implicit);
			jit_ldxi_i(JIT_R0, JIT_V0, toff);
			break;
		    case eop_lb:
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			break;
		    case eop_ld:	case eop_lc:
			fail = jit_beqi(JIT_R1, 0);
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			break;
		    default:
			abort();
		}
	    }
	    if (doint) {
		over = jit_forward();
		next = jit_bnei(JIT_R0, t_int);
		if (code == eop_noop)
		    maybe_reload_ireg_implicit();
		else
		    load_ireg(JIT_R1, voff);
#  if __WORDSIZE == 32
		temp = null;
		if (east_node(ast1)->code == eop_inc) {
		    temp = jit_bxaddi_u(JIT_V1, 1);
		    jump = jit_boaddi(JIT_V2, 1);
		}
		else {
		    temp = jit_bxsubi_u(JIT_V1, 1);
		    jump = jit_bosubi(JIT_V2, 1);
		}
		if (temp)
		    jit_patch(temp);
#  else
		if (east_node(ast1)->code == eop_inc)
		    jump = jit_boaddi(JIT_V1, 1);
		else
		    jump = jit_bosubi(JIT_V1, 1);
#  endif
		jit_patch_at(jump, over);
		store_ireg_implicit(true);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (doflt) {
		if (next)
		    jit_patch(next);
		next = jit_bnei(JIT_R0, t_float);
		if (code == eop_noop)
		    maybe_reload_freg_implicit();
		else
		    load_freg(JIT_R1, voff);
		if (east_node(ast1)->code == eop_inc)
		    jit_addi_d(JIT_F0, JIT_F0, 1.0);
		else
		    jit_subi_d(JIT_F0, JIT_F0, 1.0);
		store_freg_implicit(true);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	overflow:
	    if (next)
		jit_patch(next);
	    if (fail)
		jit_patch(fail);
	    if (over)
		jit_link(over);
	    switch (code) {
		case eop_noop:						break;
		case eop_ld:	call_vi(evm_ld, soff);			break;
		case eop_ldt:	call_vii(evm_ldt, soff, type);		break;
		case eop_lb:	call_vi(evm_lb, soff);			break;
		case eop_lbt:	call_vii(evm_lbt, soff, type);		break;
		case eop_lc:	call_vii(evm_lc, soff, type);		break;
		default:	abort();
	    }
	    jit_calli(east_node(ast1)->code == eop_inc ? evm_inc : evm_dec);
	    next = jump = null;
	    if (!(kind & (ri64|ru64)) && (kind & iint)) {
		/* reload if coerced back to integer */
		jit_ldxi_i(JIT_R0, JIT_V0,
			   offsetof(ethread_t, r0) + offsetof(evalue_t, t));
		next = jit_bnei(JIT_R0, t_int);
		load_ireg_implicit();
		jump = jit_jmpi();
	    }
	    else
		DEBUG_IMPLICIT_TYPE_INT();
	    if (kind & irel) {
		if (next)
		    jit_patch(next);
		next = jit_bnei(JIT_R0, t_float);
		load_freg_implicit();
	    }
	    else
		DEBUG_IMPLICIT_TYPE_FLOAT();
	    if (jump)
		jit_patch(jump);
	    if (next)
		jit_patch(next);
	    if (done)
		jit_link(done);
	    ejit_sync = ejit_sync_register|ejit_sync_dynamic|
			ejit_sync_implicit|ejit_sync_int_ext;
	    break;
    }
    ejit_type = ast1->itype;
}

static void
emit_load_incdec_store(east_list_t *ast0, east_list_t *ast1,  east_list_t *ast2)
{
    eint32_t		 kind;
#  define sync_type	 1
#  define sync_value	 2
    eint32_t		 sync;
    ebool_t		 same;
    jit_node_t		*done;
    jit_node_t		*fail,  *jump;
    jit_node_t		*next,  *over;
    jit_node_t		*rfail, *temp;
    ecode_t		 lcode,  rcode;
    eint32_t		 lsoff,  rsoff;
    eint32_t		 ltoff;
    eint32_t		 lvoff,  rvoff;
    etype_t		 ltype,  rtype;
    ebool_t		 lcdyn,  rcdyn;
    jit_int32_t		 lbase,  rbase, tbase;
    ebool_t		 doint,  doflt;

    lbase = rbase = tbase = JIT_R1;
    done = fail = next = over = null;
    lcdyn = rcdyn = false;
    rcode = east_node(ast2)->code;
    if (ast0) {
	kind = ast0->itype;
	lsoff = east_node(ast0)->csymbol.symbol->offset;
	ltype = east_node(ast0)->csymbol.symbol->type;
	switch (lcode = east_node(ast0)->code) {
	    case eop_ld:	case eop_ldt:
		same = ((rcode == eop_sd || rcode == eop_sdt) &&
			east_node(ast2)->csymbol.symbol ==
			east_node(ast0)->csymbol.symbol);
		ltoff = -4;	lvoff = 0;
		break;
	    case eop_lb:	case eop_lbt:
		same = ((rcode == eop_sb || rcode == eop_sbt) &&
			east_node(ast2)->csymbol.symbol ==
			east_node(ast0)->csymbol.symbol);
		ltoff = lsoff * sizeof(evalue_t) + offsetof(evalue_t, t);
		lvoff = lsoff * sizeof(evalue_t) + offsetof(evalue_t, v.o);
		break;
	    case eop_lc:
		same = (rcode == eop_sc &&
			east_node(ast2)->csymbol.symbol ==
			east_node(ast0)->csymbol.symbol);
		lcdyn = ltype == t_void || ltype > elast_basic_type;
		ltoff = -4;	lvoff = lsoff;
		break;
	    default:
		abort();
	}
    }
    else {
	same = false;
	lsoff = 0;		lcode = eop_noop;
	kind = ltype = ast1->rtype;
	ltoff = offsetof(ethread_t, r0) + offsetof(evalue_t, t);
	lvoff = offsetof(ethread_t, r0) + offsetof(evalue_t, v.o);
    }
    switch (kind) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    kind = ri32;		break;
	case t_uint32:	case t_int:
	    kind = ri64;		break;
	case t_uint:
	    kind = ru64;		break;
	case t_float32:
	    kind = rf32;		break;
	case t_float64:
	    kind = rf64;		break;
	case t_exact:
	    kind = rint;		break;
	case t_inexact:
	    kind = rrel;		break;
	case t_dynamic:
	    kind = rint|rrel;		break;
	default:
	    kind = 0;			break;
    }
    switch (ast1->itype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    kind |= ii32;		break;
	case t_uint32:	case t_int:
	    kind |= ii64;		break;
	case t_uint:	case t_exact:
	    kind |= iint;		break;
	case t_float64:
	    kind |= if64;		break;
	case t_inexact:
	    kind |= irel;		break;
	case t_dynamic:
	    kind |= iint|irel;		break;
	default:			break;
    }
    if (same) {
	rtype = ltype;		rsoff = lsoff;
	rvoff = lvoff;		rcdyn = lcdyn;
    }
    else {
	rtype = east_node(ast2)->csymbol.symbol->type;
	rsoff = east_node(ast2)->csymbol.symbol->offset;
	switch (rcode) {
	    case eop_sd:	case eop_sdt:
		rvoff = 0;
		break;
	    case eop_sb:	case eop_sbt:
		rvoff = rsoff * sizeof(evalue_t) + offsetof(evalue_t, v.o);
		break;
	    case eop_sc:
		rvoff = rsoff;
		rcdyn = rtype == t_void || rtype > elast_basic_type;
		break;
	    default:
		abort();
	}
    }
    doint = !!(kind & (ri32|ri64|ru64|rint));
    doflt = !!(kind & (rf32|rf64|rrel));
    if (doint || doflt) {
	switch (lcode) {
	    case eop_noop:
		lbase = JIT_V0;
		break;
	    case eop_ld:	case eop_ldt:
		lbase = JIT_R1;
		jit_ldi(lbase, (jit_word_t)
			(eint8_t *)eds + lsoff * sizeof(eobject_t));
		break;
	    case eop_lb:	case eop_lbt:
		lbase = JIT_R1;
		jit_ldxi(lbase, JIT_V0, offsetof(ethread_t, ebp));
		break;
	    case eop_lc:
		lbase = JIT_R1;
		jit_ldxi(lbase, JIT_V0, offsetof(ethread_t, ebp));
		switch (rcode) {
		    case eop_sd:	case eop_sdt:	case eop_sc:
			/* pointer to 'this' */
			jit_ldxi(lbase, lbase,
				 -2 * sizeof(evalue_t) +
				 offsetof(evalue_t, v.o));
			break;
		    case eop_sb:	case eop_sbt:
			/* cannot be same */
			rbase = JIT_R1;	lbase = JIT_R2;
			jit_ldxi(lbase, rbase,
				 -2 * sizeof(evalue_t) +
				 offsetof(evalue_t, v.o));
			break;
		    default:
			abort();
		}
		break;
	    default:
		abort();
	}
	if (same) {
	    rbase = tbase = lbase;
	    if (lcdyn) {
		jit_ldxi(lbase, lbase, lsoff);
		lvoff = rvoff = 0;
	    }
	}
	else {
	    switch (rcode) {
		case eop_sd:
		    rbase = lcode == eop_noop ? JIT_R1 : JIT_R2;
		    /* movi not ldi because need pointer to object address */
		    jit_movi(rbase, (jit_word_t)
			    (eint8_t *)eds + rsoff * sizeof(eobject_t));
		    break;
		case eop_sdt:
		    /* statically typed globals still allocate an
		     * object, just that it is guaranteed to not
		     * be null (at some point, should use a record
		     * object for globals/namespaces and then not
		     * allocate extra memory for statically typed
		     * objects) */
		    rbase = lcode == eop_noop ? JIT_R1 : JIT_R2;
		    jit_ldi(rbase, (jit_word_t)
			    (eint8_t *)eds + rsoff * sizeof(eobject_t));
		    break;
		case eop_sb:	case eop_sbt:
		    switch (lcode) {
			case eop_noop:
			    rbase = JIT_R1;
			    jit_ldxi(rbase, JIT_V0, offsetof(ethread_t, ebp));
			    break;
			case eop_ld:	case eop_ldt:
			    rbase = JIT_R2;
			    jit_ldxi(rbase, JIT_V0, offsetof(ethread_t, ebp));
			    break;
			case eop_lb:	case eop_lbt:
			    rbase = lbase;
			    break;
			case eop_lc:
			    /* rbase already set */
			    break;
			default:
			    abort();
		    }
		    break;
		case eop_sc:
		    switch (lcode) {
			case eop_noop:
			    rbase = JIT_R1;
			    goto store_class;
			case eop_ld:	case eop_ldt:
			    rbase = JIT_R2;
			store_class:
			    jit_ldxi(rbase, JIT_V0, offsetof(ethread_t, ebp));
			    jit_ldxi(rbase, rbase,
				     -2 * sizeof(evalue_t) +
				     offsetof(evalue_t, v.o));
			    break;
			case eop_lb:	case eop_lbt:
			    rbase = JIT_R2;
			    jit_ldxi(rbase, lbase,
				     -2 * sizeof(evalue_t) +
				     offsetof(evalue_t, v.o));
			    break;
			case eop_lc:
			    rbase = lbase;
			    break;
			default:
			    abort();
		    }
		    break;
		default:
		    abort();
	    }
	    if (rcdyn) {
		/* addi not ldxi because need pointer to object address */
		if (lcode == eop_noop)
		    jit_addi(rbase, rbase, rvoff);
		else {
		    jit_addi(JIT_R2, rbase, rvoff);
		    rbase = JIT_R2;
		}
		rvoff = 0;
	    }
	    if (lcdyn) {
		jit_ldxi(lbase, lbase, lvoff);
		lvoff = 0;
	    }
	    tbase = rbase == JIT_R1 ? JIT_R2 : JIT_R1;
	}
    }
    switch (kind) {
	case ri32|ii32:
	    switch (lcode) {
		case eop_noop:
		    maybe_reload_ireg32_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg(lbase, lvoff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(lbase, lvoff, ltype);
		    break;
		default:
		    abort();
	    }
	    if (east_node(ast1)->code == eop_inc)
		jit_addi(JIT_V1, JIT_V1, 1);
	    else
		jit_subi(JIT_V1, JIT_V1, 1);
	    ejit_sync = ejit_sync_register;
	    switch (rcode) {
		case eop_sd:
		dynamic_int_one:
		    zero_sign_extend(ltype);
		    assert(rvoff == 0);
		    if (same)
			store_ireg(rbase, 0);
		    else {
			store_ireg_implicit(lcode != eop_noop ||
					    !(ejit_sync & ejit_sync_implicit));
			jit_ldr(tbase, rbase);
			rfail = jit_beqi(tbase, 0);
			jit_ldxi(JIT_R0, tbase, -4);
			temp = jit_bnei(JIT_R0, t_int);
			store_ireg(tbase, 0);
			jump = jit_jmpi();
			jit_patch(rfail);
			jit_patch(temp);
			jit_prepare(jit_call_default);
			jit_pushargr(rbase);
			jit_finishi(evm_store_pointer_int);
			jit_patch(jump);
			ejit_sync |= ejit_sync_implicit;
		    }
		    ejit_sync |= ejit_sync_int_ext;
		    break;
		case eop_sb:
		    zero_sign_extend(ltype);
		    if (same)
			store_ireg(rbase, rvoff);
		    else
			store_ireg_value_type(rbase, rvoff -
					      offsetof(evalue_t, v.o));
		    ejit_sync |= ejit_sync_int_ext;
		    break;
		case eop_sdt:	case eop_sbt:
		static_int_one:
		    store_int32(rbase, rvoff, rtype);
		    break;
		case eop_sc:
		    if (rcdyn)
			goto dynamic_int_one;
		    goto static_int_one;
		default:
		    abort();
	    }
	    break;
	case ri32|ii64:		case ri64|ii64:
	    switch (lcode) {
		case eop_noop:
		    maybe_reload_extend_ireg_implicit(ltype);
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg(lbase, lvoff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(lbase, lvoff, ltype);
		    zero_sign_extend(ltype);
		    break;
		default:
		    abort();
	    }
#  if __WORDSIZE == 32
	    if (east_node(ast1)->code == eop_inc) {
		jump = jit_bxaddi_u(JIT_V1, 1);
		jit_addi(JIT_V2, JIT_V2, 1);
	    }
	    else {
		jump = jit_bxsubi_u(JIT_V1, 1);
		jit_subi(JIT_V2, JIT_V2, 1);
	    }
	    jit_patch(jump);
#  else
	    if (east_node(ast1)->code == eop_inc)
		jit_addi(JIT_V1, JIT_V1, 1);
	    else
		jit_subi(JIT_V1, JIT_V1, 1);
#  endif
	    ejit_sync = ejit_sync_register|ejit_sync_int_ext;
	    switch (rcode) {
		case eop_sd:
		dynamic_int_two:
		    assert(rvoff == 0);
		    if (same)
			store_ireg(rbase, 0);
		    else {
			store_ireg_implicit(lcode != eop_noop ||
					    !(ejit_sync & ejit_sync_implicit));
			jit_ldr(tbase, rbase);
			rfail = jit_beqi(tbase, 0);
			jit_ldxi(JIT_R0, tbase, -4);
			temp = jit_bnei(JIT_R0, t_int);
			store_ireg(tbase, 0);
			jump = jit_jmpi();
			jit_patch(rfail);
			jit_patch(temp);
			jit_prepare(jit_call_default);
			jit_pushargr(rbase);
			jit_finishi(evm_store_pointer_int);
			jit_patch(jump);
			ejit_sync |= ejit_sync_implicit;
		    }
		    break;
		case eop_sb:
		    if (same)
			store_ireg(rbase, rvoff);
		    else
			store_ireg_value_type(rbase, rvoff -
					      offsetof(evalue_t, v.o));
		    break;
		case eop_sdt:	case eop_sbt:
		static_int_two:
		    store_int(rbase, rvoff, rtype);
		    break;
		case eop_sc:
		    if (rcdyn)
			goto dynamic_int_two;
		    goto static_int_two;
		default:
		    abort();
	    }
	    break;
	case ri64|iint:		case ru64|iint:
	    done = jit_forward();
	    over = jit_forward();
	    switch (lcode) {
		case eop_noop:
		    if (!(ejit_sync & ejit_sync_implicit)) {
			assert(ejit_sync & ejit_sync_register);
			store_ireg_implicit(true);
		    }
		    else
			maybe_reload_extend_ireg_implicit(ltype);
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg(lbase, lvoff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(lbase, lvoff, ltype);
		    zero_sign_extend(ltype);
		    break;
		default:
		    abort();
	    }
#  if __WORDSIZE == 32
	    if (east_node(ast1)->code == eop_inc) {
		if (kind & ru64) {
		    jit_addci(JIT_V1, JIT_V1, 1);
		    jit_addxi(JIT_V2, JIT_V2, 0);
		    jump = jit_blti(JIT_V2, 0);
		}
		else {
		    temp = jit_bxaddi_u(JIT_V1, 1);
		    jump = jit_boaddi(JIT_V2, 1);
		    jit_patch(temp);
		}
	    }
	    else {
		if (kind & ru64) {
		    jit_subci(JIT_V1, JIT_V1, 1);
		    jit_subxi(JIT_V2, JIT_V2, 0);
		    jump = jit_blti(JIT_V2, 0);
		}
		else {
		    temp = jit_bxsubi_u(JIT_V1, 1);
		    jump = jit_bosubi(JIT_V2, 1);
		    jit_patch(temp);
		}
	    }
#  else
	    if (east_node(ast1)->code == eop_inc) {
		if (kind & ru64) {
		    jit_addi(JIT_V1, JIT_V1, 1);
		    jump = jit_blti(JIT_V1, 0);
		}
		else
		    jump = jit_boaddi(JIT_V1, 1);
	    }
	    else {
		if (kind & ru64) {
		    jit_subi(JIT_V1, JIT_V1, 1);
		    jump = jit_blti(JIT_V1, 0);
		}
		else
		    jump = jit_bosubi(JIT_V1, 1);
	    }
#  endif
	    jit_patch_at(jump, over);
	    switch (rcode) {
		case eop_sd:
		dynamic_int_three:
		    assert(rvoff == 0);
		    if (same)
			store_ireg(rbase, 0);
		    else {
			store_ireg_implicit(lcode != eop_noop ||
					    !(ejit_sync & ejit_sync_implicit));
			jit_ldr(tbase, rbase);
			rfail = jit_beqi(tbase, 0);
			jit_ldxi(JIT_R0, tbase, -4);
			temp = jit_bnei(JIT_R0, t_int);
			store_ireg(tbase, 0);
			jump = jit_jmpi();
			jit_patch_at(jump, done);
			jit_patch(rfail);
			jit_patch(temp);
			jit_prepare(jit_call_default);
			jit_pushargr(rbase);
			jit_finishi(evm_store_pointer_int);
		    }
		    break;
		case eop_sb:
		    if (same)
			store_ireg(rbase, rvoff);
		    else
			store_ireg_value_type(rbase, rvoff -
					      offsetof(evalue_t, v.o));
		    break;
		case eop_sdt:	case eop_sbt:
		static_int_three:
		    store_int(rbase, rvoff, rtype);
		    break;
		case eop_sc:
		    if (rcdyn)
			goto dynamic_int_three;
		    goto static_int_three;
		default:
		    abort();
	    }
	    if (east_node(ast2)->csimple.flags & code_flags_implicit)
		store_ireg_implicit(!rcdyn &&
				    (lcode != eop_noop ||
				     !(ejit_sync & ejit_sync_implicit)));
	    jump = jit_jmpi();
	    jit_patch_at(jump, done);
	    goto overflow;
	case rf32|if64:
	    if (lcode == eop_noop) {
		if (!(ejit_sync & ejit_sync_register)) {
		    assert(ejit_sync & ejit_sync_implicit);
		    load_freg_implicit();
		}
		else if (!(ejit_sync_float_ext))
		    jit_extr_f_d(JIT_F0, JIT_F1);
	    }
	    else {
		load_freg_type(lbase, lvoff, t_float32);
		jit_extr_f_d(JIT_F0, JIT_F1);
	    }
	    goto incdec_float;
	case rf64|if64:
	    if (lcode == eop_noop)
		maybe_reload_freg_implicit();
	    else
		load_freg(lbase, lvoff);
	incdec_float:
	    if (east_node(ast1)->code == eop_inc)
		jit_addi_d(JIT_F0, JIT_F0, 1.0);
	    else
		jit_subi_d(JIT_F0, JIT_F0, 1.0);
	    ejit_sync = ejit_sync_register;
	    switch (rcode) {
		case eop_sd:
		dynamic_float_one:
		    assert(rvoff == 0);
		    if (same)
			store_freg(rbase, 0);
		    else {
			store_freg_implicit(lcode != eop_noop ||
					    !(ejit_sync & ejit_sync_implicit));
			jit_ldr(tbase, rbase);
			rfail = jit_beqi(tbase, 0);
			jit_ldxi(JIT_R0, tbase, -4);
			temp = jit_bnei(JIT_R0, t_float);
			store_freg(tbase, 0);
			jump = jit_jmpi();
			jit_patch(rfail);
			jit_patch(temp);
			jit_prepare(jit_call_default);
			jit_pushargr(rbase);
			jit_finishi(evm_store_pointer_float);
			/* assume no callee save float register */
			if (east_node(ast2)->csimple.flags &
			    code_flags_implicit)
			    load_freg_implicit();
			jit_patch(jump);
			ejit_sync |= ejit_sync_implicit;
		    }
		    break;
		case eop_sb:
		    if (same)
			store_freg(rbase, rvoff);
		    else
			store_freg_value_type(rbase, rvoff -
					      offsetof(evalue_t, v.o));
		    break;
		case eop_sdt:	case eop_sbt:
		static_float_one:
		    store_float(rbase, rvoff, rtype);
		    break;
		case eop_sc:
		    if (rcdyn)
			goto dynamic_float_one;
		    goto static_float_one;
		    break;
		default:
		    abort();
	    }
	    break;
	default:
	    if (doint || doflt) {
		done = jit_forward();
		switch (lcode) {
		    case eop_noop:
			assert(ejit_sync & ejit_sync_implicit);
			jit_ldxi_i(JIT_R0, JIT_V0, ltoff);
			break;
		    case eop_lb:
			jit_ldxi_i(JIT_R0, JIT_R1, ltoff);
			break;
		    case eop_ld:	case eop_lc:
			fail = jit_beqi(JIT_R1, 0);
			jit_ldxi_i(JIT_R0, JIT_R1, ltoff);
			break;
		    default:
			abort();
		}
	    }
	    if (doint) {
		over = jit_forward();
		next = jit_bnei(JIT_R0, t_int);
		if (lcode == eop_noop) {
		    if (!(ejit_sync & ejit_sync_implicit)) {
			assert(ejit_sync & ejit_sync_register);
			store_ireg_implicit(true);
		    }
		    else
			maybe_reload_ireg_implicit();
		    sync = sync_value;
		}
		else {
		    load_ireg(lbase, lvoff);
		    sync = sync_type|sync_value;
		}
#  if __WORDSIZE == 32
		temp = null;
		if (east_node(ast1)->code == eop_inc) {
		    temp = jit_bxaddi_u(JIT_V1, 1);
		    jump = jit_boaddi(JIT_V2, 1);
		}
		else {
		    temp = jit_bxsubi_u(JIT_V1, 1);
		    jump = jit_bosubi(JIT_V2, 1);
		}
		if (temp)
		    jit_patch(temp);
#  else
		if (east_node(ast1)->code == eop_inc)
		    jump = jit_boaddi(JIT_V1, 1);
		else
		    jump = jit_bosubi(JIT_V1, 1);
#  endif
		jit_patch_at(jump, over);
		switch (rcode) {
		    case eop_sd:
		    dynamic_int_four:
			assert(rvoff == 0);
			if (same)
			    store_ireg(rbase, 0);
			else {
			    store_ireg_implicit(sync & sync_type);
			    jit_ldr(tbase, rbase);
			    rfail = jit_beqi(tbase, 0);
			    jit_ldxi(JIT_R0, tbase, -4);
			    temp = jit_bnei(JIT_R0, t_int);
			    store_ireg(tbase, 0);
			    jump = jit_jmpi();
			    jit_patch_at(jump, done);
			    jit_patch(rfail);
			    jit_patch(temp);
			    jit_prepare(jit_call_default);
			    jit_pushargr(rbase);
			    jit_finishi(evm_store_pointer_int);
			    sync = 0;
			}
			break;
		    case eop_sb:
			if (same)
			    store_ireg(rbase, rvoff);
			else
			    store_ireg_value_type(rbase, rvoff -
						  offsetof(evalue_t, v.o));
			    break;
		    case eop_sdt:	case eop_sbt:
		    static_int_four:
			store_int(rbase, rvoff, rtype);
			break;
		    case eop_sc:
			if (rcdyn)
			    goto dynamic_int_four;
			goto static_int_four;
		    default:
			abort();
		}
		if ((sync & sync_value) &&
		    (east_node(ast2)->csimple.flags & code_flags_implicit))
		    store_ireg_implicit(sync & sync_type);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (doflt) {
		if (next)
		    jit_patch(next);
		next = jit_bnei(JIT_R0, t_float);
		if (lcode == eop_noop) {
		    if (!(ejit_sync & ejit_sync_implicit)) {
			assert(ejit_sync & ejit_sync_register);
			store_freg_implicit(true);
		    }
		    else
			maybe_reload_freg_implicit();
		    sync = sync_value;
		}
		else {
		    load_freg(lbase, lvoff);
		    sync = sync_type|sync_value;
		}
		if (east_node(ast1)->code == eop_inc)
		    jit_addi_d(JIT_F0, JIT_F0, 1.0);
		else
		    jit_subi_d(JIT_F0, JIT_F0, 1.0);
		switch (rcode) {
		    case eop_sd:
		    dynamic_float_two:
			assert(rvoff == 0);
			if (same)
			    store_freg(rbase, 0);
			else {
			    store_freg_implicit(sync & sync_type);
			    jit_ldr(tbase, rbase);
			    rfail = jit_beqi(tbase, 0);
			    jit_ldxi(JIT_R0, tbase, -4);
			    temp = jit_bnei(JIT_R0, t_float);
			    store_freg(tbase, 0);
			    jump = jit_jmpi();
			    jit_patch_at(jump, done);
			    jit_patch(rfail);
			    jit_patch(temp);
			    jit_prepare(jit_call_default);
			    jit_pushargr(rbase);
			    jit_finishi(evm_store_pointer_float);
			    /* assume no callee save float register */
			    if (east_node(ast2)->csimple.flags &
				code_flags_implicit)
				load_freg_implicit();
			}
			break;
		    case eop_sb:
			if (same)
			    store_freg(rbase, rvoff);
			else
			    store_freg_value_type(rbase, rvoff -
						  offsetof(evalue_t, v.o));
			    break;
		    case eop_sdt:	case eop_sbt:
		    static_float_two:
			store_float(rbase, rvoff, rtype);
			break;
		    case eop_sc:
			if (rcdyn)
			    goto dynamic_float_two;
			goto static_float_two;
		    default:
			abort();
		}
		if ((sync & sync_value) &&
		    (east_node(ast2)->csimple.flags & code_flags_implicit))
		    store_freg_implicit(sync & sync_type);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	overflow:
	    if (next)
		jit_patch(next);
	    if (fail)
		jit_patch(fail);
	    if (over)
		jit_link(over);
	    switch (lcode) {
		case eop_noop:						break;
		case eop_ld:	call_vi(evm_ld, lsoff);			break;
		case eop_ldt:	call_vii(evm_ldt, lsoff, ltype);	break;
		case eop_lb:	call_vi(evm_lb, lsoff);			break;
		case eop_lbt:	call_vii(evm_lbt, lsoff, ltype);	break;
		case eop_lc:	call_vii(evm_lc, lsoff, ltype);		break;
		default:	abort();
	    }
	    jit_calli(east_node(ast1)->code == eop_inc ? evm_inc : evm_dec);
	    switch (rcode) {
		case eop_sd:	call_vi(evm_sd, rsoff);			break;
		case eop_sdt:	call_vii(evm_sdt, rsoff, rtype);	break;
		case eop_sb:	call_vi(evm_sb, rsoff);			break;
		case eop_sbt:	call_vii(evm_sbt, rsoff, rtype);	break;
		case eop_sc:	call_vii(evm_sc, rsoff, rtype);		break;
		default:	abort();
	    }
	    if (east_node(ast2)->csimple.flags & code_flags_implicit) {
		next = jump = null;
		/* reload if used and coerced back to integer */
		if (!(kind & (ri64|ru64)) && (kind & iint)) {
		    jit_ldxi_i(JIT_R0, JIT_V0,
			       offsetof(ethread_t, r0) + offsetof(evalue_t, t));
		    next = jit_bnei(JIT_R0, t_int);
		    load_ireg_implicit();
		    jit_patch(next);
		}
		else
		    DEBUG_IMPLICIT_TYPE_INT();
		if (kind & irel) {
		    if (next)
			jit_patch(next);
		    next = jit_bnei(JIT_R0, t_float);
		    load_freg_implicit();
		}
		else
		    DEBUG_IMPLICIT_TYPE_FLOAT();
		if (jump)
		    jit_patch(jump);
		if (next)
		    jit_patch(next);
	    }
	    if (done)
		jit_link(done);
	    ejit_sync = ejit_sync_register|ejit_sync_dynamic|
			ejit_sync_implicit|ejit_sync_int_ext;
	    break;
    }
    ejit_type = ast2->itype;
#  undef sync_value
#  undef sync_type
}

static void
emit_load_push(east_list_t *ast0, east_list_t *ast1)
{
    jit_node_t		*done;
    jit_node_t		*jump;
    jit_node_t		*next;
    jit_node_t		*fail;
    eint32_t		 kind;
    eint32_t		 soff;
    eint32_t		 toff;
    eint32_t		 voff;

    next = done = fail = null;
    switch (ast0->itype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:	case t_uint32:	case t_int:
	    kind = ii64;		break;
	case t_uint:
	    kind = iu64;		break;
	case t_float32:
	    kind = if32;		break;
	case t_float:
	    kind = if64;		break;
	case t_exact:
	    kind = iint;		break;
	case t_inexact:
	    kind = irel;		break;
	case t_dynamic:
	    kind = iint|irel;		break;
	default:
	    kind = 0;			break;
    }
    soff = east_node(ast0)->csymbol.symbol->offset;
    switch (east_node(ast0)->code) {
	case eop_ld:	case eop_ldt:
	    if (kind)
		jit_ldi(JIT_R1, (jit_word_t)
			(eint8_t *)eds + soff * sizeof(eobject_t));
	    toff = -4;
	    voff = 0;
	    break;
	case eop_lb:	case eop_lbt:
	    if (kind)
		jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
	    toff = soff * sizeof(evalue_t) + offsetof(evalue_t, t);
	    voff = soff * sizeof(evalue_t) + offsetof(evalue_t, v.o);
	    break;
	case eop_lc:
	    if (kind) {
		jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
		/* pointer to 'this' */
		jit_ldxi(JIT_R1, JIT_R1,
			 -2 * sizeof(evalue_t) + offsetof(evalue_t, v.o));
	    }
	    toff = -4;
	    voff = soff;
	    break;
	default:
	    abort();
    }
    jit_ldxi(JIT_R2, JIT_V0, offsetof(ethread_t, esp));
    jit_addi(JIT_R0, JIT_R2, sizeof(evalue_t));
    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_R0);
    switch (kind) {
	case ii64:	case iu64:
	    switch (east_node(ast0)->code) {
		case eop_ld:	case eop_lb:
		    load_ireg(JIT_R1, voff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(JIT_R1, voff, ast0->itype);
		    zero_sign_extend(ast0->itype);
		    break;
		default:
		    abort();
	    }
	    if (kind == iu64) {
#  if __WORDSIZE == 32
		next = jit_blti(JIT_V2, 0);
#  else
		next = jit_blti(JIT_V1, 0);
#  endif
	    }
	    store_ireg_value_type(JIT_R2, 0);
	    if (east_node(ast1)->csimple.flags & code_flags_implicit)
		store_ireg_implicit(true);
	    if (kind == iu64) {
		done = jit_forward();
		jump = jit_jmpi();
		jit_patch_at(jump, done);
		jit_patch(next);
#if __WORDSIZE == 32
		store_ireg_implicit_rgz(RGZ_r2_to_v1, JIT_V1, JIT_V2);
#else
		store_ireg_implicit_rgz(RGZ_r2_to_v1, JIT_V1);
#endif
		goto overflow;
	    }
	    ejit_sync = ejit_sync_register|ejit_sync_int_ext;
	    break;
	case if32:
	    ejit_sync = ejit_sync_register|ejit_sync_float_ext;
	    load_freg_type(JIT_R1, voff, t_float32);
	    jit_extr_f_d(JIT_F0, JIT_F1);
	    goto push_float;
	    break;
	case if64:
	    ejit_sync = ejit_sync_register;
	    load_freg(JIT_R1, voff);
	push_float:
	    store_freg_value_type(JIT_R2, 0);
	    if (east_node(ast1)->csimple.flags & code_flags_implicit)
		store_freg_implicit(true);
	    break;
	default:
	    if (kind) {
		done = jit_forward();
		switch (east_node(ast0)->code) {
		    case eop_lb:
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			break;
		    case eop_ld:
			fail = jit_beqi(JIT_R1, 0);
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			break;
		    case eop_lc:
			jit_ldxi(JIT_R1, JIT_R1, voff);
			/* if null
			 * could short circuit but generate smaller
			 * code as load of null should be uncommon */
			fail = jit_beqi(JIT_R1, 0);
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			voff = 0;
			break;
		    default:
			abort();
		}
	    }
	    if (kind & iint) {
		next = jit_bnei(JIT_R0, t_int);
		load_ireg(JIT_R1, voff);
		if (east_node(ast1)->csimple.flags & code_flags_implicit)
		    store_ireg_implicit(true);
		store_ireg_value_type(JIT_R2, 0);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (kind & irel) {
		if (next)
		    jit_patch(next);
		next = jit_bnei(JIT_R0, t_float);
		load_freg(JIT_R1, voff);
		if (east_node(ast1)->csimple.flags & code_flags_implicit)
		    store_freg_implicit(true);
		store_freg_value_type(JIT_R2, 0);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (next)
		jit_patch(next);
	    if (fail)
		jit_patch(fail);
	    jit_movr(JIT_V1, JIT_R2);
	    switch (east_node(ast0)->code) {
		case eop_ld:
		    call_vi(evm_ld, soff);
		    break;
		case eop_lb:
		    call_vi(evm_lb, soff);
		    break;
		case eop_lc:
		    call_vii(evm_lc, soff, ast0->itype);
		    break;
		default:
		    abort();
	    }
	    DEBUG_IMPLICIT_TYPE();
	overflow:
	    jit_prepare(jit_call_default);
	    jit_pushargr(JIT_V1);
	    if (east_node(ast1)->code == eop_push)
		jit_finishi(evm_store_value_push);
	    else
		jit_finishi(evm_store_value_copy);
	    if (done)
		jit_link(done);
	    ejit_sync = ejit_sync_register|ejit_sync_dynamic|
			ejit_sync_implicit|ejit_sync_int_ext;
    }
    ejit_type = ast1->itype;
}

static void
emit_load_push_int_cmp(east_list_t *ast0, east_list_t *ast1,
		       east_list_t *ast2, east_list_t *ast3)
{
    edata_t		 data;
    jit_node_t		*done;
    jit_node_t		*jump;
    jit_node_t		*load;
    jit_node_t		*next;
#  if __WORDSIZE == 32
    jit_node_t		*temp;
#  endif
    ebool_t		 cdyn;
    eint32_t		 kind;
    ecode_t		 code;
    eint32_t		 soff;
    eint32_t		 toff;
    eint32_t		 voff;
    etype_t		 type;
    ebool_t		 doint;
    ebool_t		 doflt;

    cdyn = false;
    data.L = immediate_int(east_node(ast2));
    if (ast0) {
	kind = ast0->itype;
	soff = east_node(ast0)->csymbol.symbol->offset;
	type = east_node(ast0)->csymbol.symbol->type;
	switch (code = east_node(ast0)->code) {
	    case eop_ld:	case eop_ldt:
		toff = -4;
		voff = 0;
		break;
	    case eop_lb:	case eop_lbt:
		toff = soff * sizeof(evalue_t) + offsetof(evalue_t, t);
		voff = soff * sizeof(evalue_t) + offsetof(evalue_t, v.o);
		break;
	    case eop_lc:
		toff = -4;
		voff = soff;
		cdyn = type == t_void || type > elast_basic_type;
		break;
	    default:
		abort();
	}
    }
    else {
	soff = 0;
	code = eop_noop;
	kind = type = ast1->rtype;
	toff = offsetof(ethread_t, r0) + offsetof(evalue_t, t);
	voff = offsetof(ethread_t, r0) + offsetof(evalue_t, v.o);
    }
    switch (kind) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    if (east_node(ast2)->code == eop_int) {
		kind = ii32;		break;
	    }
	    /* FALLTHROUGH */
	case t_uint32:	case t_int:
	    kind = ii64;		break;
	case t_uint:
	    kind = iu64;		break;
	case t_exact:
	    kind = iint;		break;
	case t_float32:
	    kind = if32;		break;
	case t_float:
	    kind = if64;		break;
	case t_inexact:
	    kind = irel;		break;
	case t_dynamic:
	    kind = iint|irel;		break;
	default:
	    kind = 0;			break;
    }
    doint = !!(kind & (ii32|ii64|iu64|iint));
    doflt = !!(kind & (if32|if64|irel));
    if (doint || doflt) {
	switch (code) {
	    case eop_noop:
		break;
	    case eop_ld:	case eop_ldt:
		jit_ldi(JIT_R1, (jit_word_t)
			(eint8_t *)eds + soff * sizeof(eobject_t));
		break;
	    case eop_lb:	case eop_lbt:
		jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
		break;
	    case eop_lc:
		jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
		/* pointer to 'this' */
		jit_ldxi(JIT_R1, JIT_R1,
			 -2 * sizeof(evalue_t) + offsetof(evalue_t, v.o));
		if (cdyn) {
		    jit_ldxi(JIT_R1, JIT_R1, voff);
		    voff = 0;
		}
		break;
	    default:
		abort();
	}
    }
    switch (kind) {
	case ii32:
	    switch (code) {
		case eop_noop:
		    maybe_reload_ireg32_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg(JIT_R1, voff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(JIT_R1, voff, type);
		    break;
		default:
		    abort();
	    }
	    switch (east_node(ast3)->code) {
		case eop_lt:	jit_lti(JIT_V1, JIT_V1, data.s.l);	break;
		case eop_le:	jit_lei(JIT_V1, JIT_V1, data.s.l);	break;
		case eop_eq:	jit_eqi(JIT_V1, JIT_V1, data.s.l);	break;
		case eop_ge:	jit_gei(JIT_V1, JIT_V1, data.s.l);	break;
		case eop_gt:	jit_gti(JIT_V1, JIT_V1, data.s.l);	break;
		default:	jit_nei(JIT_V1, JIT_V1, data.s.l);	break;
	    }
	    ejit_sync = ejit_sync_register;
	    break;
	case ii64:		case iu64:
	    switch (code) {
		case eop_noop:
		    maybe_reload_extend_ireg_implicit(type);
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg(JIT_R1, voff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(JIT_R1, voff, type);
		    zero_sign_extend(type);
		    break;
		default:
		    abort();
	    }
#  if __WORDSIZE == 32
	    if (kind == iu64)
		next = jit_blti(JIT_V2, 0);
	    switch (east_node(ast3)->code) {
		case eop_lt:
		    jump = jit_bnei(JIT_V2, data.s.h);
		    jit_lti_u(JIT_V1, JIT_V1, data.s.l);
		    temp = jit_jmpi();
		    jit_patch(jump);
		    jit_lti(JIT_V1, JIT_V2, data.s.h);
		    jit_patch(temp);
		    break;
		case eop_le:
		    jump = jit_bnei(JIT_V2, data.s.h);
		    jit_lei_u(JIT_V1, JIT_V1, data.s.l);
		    temp = jit_jmpi();
		    jit_patch(jump);
		    jit_lti(JIT_V1, JIT_V2, data.s.h);
		    jit_patch(temp);
		    break;
		case eop_eq:
		    jit_eqi(JIT_V1, JIT_V1, data.s.l);
		    jit_eqi(JIT_V2, JIT_V2, data.s.h);
		    jit_andi(JIT_V1, JIT_V1, JIT_V2);
		    break;
		case eop_ge:
		    jump = jit_bnei(JIT_V2, data.s.h);
		    jit_gei_u(JIT_V1, JIT_V1, data.s.l);
		    temp = jit_jmpi();
		    jit_patch(jump);
		    jit_gti(JIT_V1, JIT_V2, data.s.h);
		    jit_patch(temp);
		    break;
		case eop_gt:
		    jump = jit_bnei(JIT_V2, data.s.h);
		    jit_gti_u(JIT_V1, JIT_V1, data.s.l);
		    temp = jit_jmpi();
		    jit_patch(jump);
		    jit_gti(JIT_V1, JIT_V2, data.s.h);
		    jit_patch(temp);
		    break;
		default:
		    jit_nei(JIT_V1, JIT_V1, data.s.l);
		    jit_nei(JIT_V2, JIT_V2, data.s.h);
		    jit_orr(JIT_V1, JIT_V1, JIT_V2);
		    break;
	    }
	    if (kind == iu64)
		jit_movi(JIT_V2, 0);
#  else
	    if (kind == iu64)
		next = jit_blti(JIT_V1, 0);
	    switch (east_node(ast3)->code) {
		case eop_lt:	jit_lti(JIT_V1, JIT_V1, data.L);	break;
		case eop_le:	jit_lei(JIT_V1, JIT_V1, data.L);	break;
		case eop_eq:	jit_eqi(JIT_V1, JIT_V1, data.L);	break;
		case eop_ge:	jit_gei(JIT_V1, JIT_V1, data.L);	break;
		case eop_gt:	jit_gti(JIT_V1, JIT_V1, data.L);	break;
		default:	jit_nei(JIT_V1, JIT_V1, data.L);	break;
	    }
#  endif
	    if (kind == iu64) {
		store_ireg_implicit(true);
		done = jit_forward();
		jump = jit_jmpi();
		jit_patch_at(jump, done);
		jit_patch(next);
#if __WORDSIZE == 32
		store_ireg_implicit_rgz(0, JIT_V1, JIT_V2);
#else
		store_ireg_implicit_rgz(0, JIT_V1);
#endif
		goto overflow;
	    }
	    ejit_sync = ejit_sync_register;
	    break;
	case if32:
	    switch (code) {
		case eop_noop:
		    if (!(ejit_sync & ejit_sync_register))
			load_freg_implicit();
		    else if (!(ejit_sync & ejit_sync_float_ext))
			jit_extr_f_d(JIT_F0, JIT_F1);
		    break;
		case eop_lbt:	case eop_ldt:	case eop_lc:
		    load_freg_type(JIT_R1, voff, t_float32);
		    jit_extr_f_d(JIT_F0, JIT_F1);
		    break;
		default:
		    abort();
	    }
	    goto float_cmp;
	case if64:
	    switch (code) {
		case eop_noop:
		    maybe_reload_freg_implicit();
		    break;
		case eop_ld:	case eop_ldt:
		case eop_lb:	case eop_lbt:	case eop_lc:
		    load_freg(JIT_R1, voff);
		    break;
		default:
		    abort();
	    }
	float_cmp:
	    switch (east_node(ast3)->code) {
		case eop_lt:	jit_lti_d(JIT_V1, JIT_F0, data.L);	break;
		case eop_le:	jit_lei_d(JIT_V1, JIT_F0, data.L);	break;
		case eop_eq:	jit_eqi_d(JIT_V1, JIT_F0, data.L);	break;
		case eop_ge:	jit_gei_d(JIT_V1, JIT_F0, data.L);	break;
		case eop_gt:	jit_gti_d(JIT_V1, JIT_F0, data.L);	break;
		default:	jit_nei_d(JIT_V1, JIT_F0, data.L);	break;
	    }
	    ejit_sync = ejit_sync_register;
	    break;
	default:
	    if (doint || doflt) {
		load = null;
		done = jit_forward();
		switch (code) {
		    case eop_noop:
			assert(ejit_sync & ejit_sync_implicit);
			jit_ldxi_i(JIT_R0, JIT_V0, toff);
			break;
		    case eop_lb:
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			break;
		    case eop_lc:
			assert(cdyn);
		    case eop_ld:
			assert(doint);
			load = jit_forward();
			next = jit_bnei(JIT_R1, 0);
			jit_movr(JIT_V1, JIT_R1);
#  if __WORDSIZE == 32
			jit_movr(JIT_V2, JIT_R1);
#  endif
			jump = jit_jmpi();
			jit_patch_at(jump, load);
			jit_patch(next);
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			next = null;
			break;
		    default:
			abort();
		}
	    }
	    else
		done = next = null;
	    if (doint) {
		next = jit_bnei(JIT_R0, t_int);
		switch (code) {
		    case eop_noop:
			load_ireg_implicit();
			break;
		    case eop_ld:	case eop_lb:	case eop_lc:
			load_ireg(JIT_R1, voff);
			break;
		    default:
			abort();
		}
		if (load)
		    jit_link(load);
#  if __WORDSIZE == 32
		switch (east_node(ast3)->code) {
		    case eop_lt:
			jump = jit_bnei(JIT_V2, data.s.h);
			jit_lti_u(JIT_V1, JIT_V1, data.s.l);
			temp = jit_jmpi();
			jit_patch(jump);
			jit_lti(JIT_V1, JIT_V2, data.s.h);
			jit_patch(temp);
			break;
		    case eop_le:
			jump = jit_bnei(JIT_V2, data.s.h);
			jit_lei_u(JIT_V1, JIT_V1, data.s.l);
			temp = jit_jmpi();
			jit_patch(jump);
			jit_lti(JIT_V1, JIT_V2, data.s.h);
			jit_patch(temp);
			break;
		    case eop_eq:
			jit_eqi(JIT_V1, JIT_V1, data.s.l);
			jit_eqi(JIT_V2, JIT_V2, data.s.h);
			jit_andi(JIT_V1, JIT_V1, JIT_V2);
			break;
		    case eop_ge:
			jump = jit_bnei(JIT_V2, data.s.h);
			jit_gei_u(JIT_V1, JIT_V1, data.s.l);
			temp = jit_jmpi();
			jit_patch(jump);
			jit_gti(JIT_V1, JIT_V2, data.s.h);
			jit_patch(temp);
			break;
		    case eop_gt:
			jump = jit_bnei(JIT_V2, data.s.h);
			jit_gti_u(JIT_V1, JIT_V1, data.s.l);
			temp = jit_jmpi();
			jit_patch(jump);
			jit_gti(JIT_V1, JIT_V2, data.s.h);
			jit_patch(temp);
			break;
		    default:
			jit_nei(JIT_V1, JIT_V1, data.s.l);
			jit_nei(JIT_V2, JIT_V2, data.s.h);
			jit_orr(JIT_V1, JIT_V1, JIT_V2);
			break;
		}
		jit_movi(JIT_V2, 0);
#  else
		switch (east_node(ast3)->code) {
		    case eop_lt:jit_lti(JIT_V1, JIT_V1, data.L);	break;
		    case eop_le:jit_lei(JIT_V1, JIT_V1, data.L);	break;
		    case eop_eq:jit_eqi(JIT_V1, JIT_V1, data.L);	break;
		    case eop_ge:jit_gei(JIT_V1, JIT_V1, data.L);	break;
		    case eop_gt:jit_gti(JIT_V1, JIT_V1, data.L);	break;
		    default:	jit_nei(JIT_V1, JIT_V1, data.L);	break;
		}
#  endif
		store_ireg_implicit(true);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (kind & irel) {
		if (next)
		    jit_patch(next);
		next = jit_bnei(JIT_R0, t_float);
		switch (code) {
		    case eop_noop:
			maybe_reload_freg_implicit();
			break;
		    case eop_ld:	case eop_lb:	case eop_lc:
			load_freg(JIT_R1, voff);
			break;
		    default:
			abort();
		}
		switch (east_node(ast3)->code) {
		    case eop_lt:jit_lti_d(JIT_V1, JIT_F0, data.L);	break;
		    case eop_le:jit_lei_d(JIT_V1, JIT_F0, data.L);	break;
		    case eop_eq:jit_eqi_d(JIT_V1, JIT_F0, data.L);	break;
		    case eop_ge:jit_gei_d(JIT_V1, JIT_F0, data.L);	break;
		    case eop_gt:jit_gti_d(JIT_V1, JIT_F0, data.L);	break;
		    default:	jit_nei_d(JIT_V1, JIT_F0, data.L);	break;
		}
#  if __WORDSIZE == 32
		jit_movi(JIT_V2, 0);
#  endif
		store_ireg_implicit(true);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (next)
		jit_patch(next);
	    switch (code) {
		case eop_noop:
		    break;
		case eop_ld:
		    call_vi(evm_ld, soff);
		    break;
		case eop_lb:
		    call_vi(evm_lb, soff);
		    break;
		case eop_lc:
		    call_vii(evm_lc, soff,
			     east_node(ast0)->csymbol.symbol->type);
		    break;
		default:
		    abort();
	    }
	overflow:
	    jit_ldxi(JIT_V1, JIT_V0, offsetof(ethread_t, esp));
	    jit_calli(evm_push);
	    emit_int_implicit(ast2, true);
	    jit_prepare(jit_call_default);
	    jit_pushargr(JIT_V1);
	    switch (east_node(ast3)->code) {
		case eop_lt:	jit_finishi(evm_i_lt);	break;
		case eop_le:	jit_finishi(evm_i_le);	break;
		case eop_eq:	jit_finishi(evm_i_eq);	break;
		case eop_ge:	jit_finishi(evm_i_ge);	break;
		case eop_gt:	jit_finishi(evm_i_gt);	break;
		default:	jit_finishi(evm_i_ne);	break;
	    }
	    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
	    load_ireg32_implicit();
#  if __WORDSIZE == 32
	    jit_movi(JIT_V2, 0);
#  endif
	    if (done)
		jit_link(done);
	    ejit_sync = ejit_sync_register|ejit_sync_implicit|ejit_sync_int_ext;
	    break;
    }
    ejit_type = ast3->itype;
}

static void
emit_load_push_int_cmp_jmp(east_list_t *ast0, east_list_t *ast1,
			   east_list_t *ast2, east_list_t *ast3,
			   east_list_t *ast4)
{
    edata_t		 data;
    jit_node_t		*done;
    jit_node_t		*jump;
    jit_node_t		*load;
    jit_node_t		*next;
#  if __WORDSIZE == 32
    jit_node_t		*temp;
#  endif
    ebool_t		 cdyn;
    eint32_t		 kind;
    eint32_t		 soff;
    eint32_t		 toff;
    eint32_t		 voff;
    etype_t		 type;
    ecode_t		 ccode;
    ecode_t		 lcode;
    ebool_t		 doint;
    ebool_t		 doflt;
    eword_t		 index;
    elabel_t		*label;

    if (east_node(ast4)->code == eop_jt)
	ccode = east_node(ast3)->code;
    else {
	switch (east_node(ast3)->code) {
	    case eop_lt:	ccode = eop_ge;		break;
	    case eop_le:	ccode = eop_gt;		break;
	    case eop_eq:	ccode = eop_ne;		break;
	    case eop_ge:	ccode = eop_lt;		break;
	    case eop_gt:	ccode = eop_le;		break;
	    default:		ccode = eop_eq;		break;
	}
    }
    label = east_node(ast4)->clabel.label;
    if (label->value == null)
	allocate_forward_label(label);
    index = eget_fixnum(label->value);
    data.L = immediate_int(east_node(ast2));
    cdyn = false;
    if (ast0) {
	kind = ast0->itype;
	soff = east_node(ast0)->csymbol.symbol->offset;
	type = east_node(ast0)->csymbol.symbol->type;
	switch (lcode = east_node(ast0)->code) {
	    case eop_ld:	case eop_ldt:
		toff = -4;
		voff = 0;
		break;
	    case eop_lb:	case eop_lbt:
		toff = soff * sizeof(evalue_t) + offsetof(evalue_t, t);
		voff = soff * sizeof(evalue_t) + offsetof(evalue_t, v.o);
		break;
	    case eop_lc:
		toff = -4;
		voff = soff;
		cdyn = type == t_void || type > elast_basic_type;
		break;
	    default:
		abort();
	}
    }
    else {
	soff = 0;
	lcode = eop_noop;
	kind = type = ast1->rtype;
	toff = offsetof(ethread_t, r0) + offsetof(evalue_t, t);
	voff = offsetof(ethread_t, r0) + offsetof(evalue_t, v.o);
    }
    switch (kind) {
	case t_int8:	case t_uint8:	case t_int16:
	case t_uint16:	case t_int32:
	    if (east_node(ast2)->code == eop_int) {
		kind = ii32;		break;
	    }
	    /* FALLTHROUGH */
	case t_uint32:	case t_int:
	    kind = ii64;		break;
	case t_uint:
	    kind = iu64;		break;
	case t_exact:
	    kind = iint;		break;
	case t_float32:
	    kind = if32;		break;
	case t_float:
	    kind = if64;		break;
	case t_inexact:
	    kind = irel;		break;
	case t_dynamic:
	    kind = iint|irel;		break;
	default:
	    kind = 0;			break;
    }
    doint = !!(kind & (ii32|ii64|iu64|iint));
    doflt = !!(kind & (if32|if64|irel));
    if (doint || doflt) {
	switch (lcode) {
	    case eop_noop:
		break;
	    case eop_ld:	case eop_ldt:
		jit_ldi(JIT_R1, (jit_word_t)
			(eint8_t *)eds + soff * sizeof(eobject_t));
		break;
	    case eop_lb:	case eop_lbt:
		jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
		break;
	    case eop_lc:
		jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
		/* pointer to 'this' */
		jit_ldxi(JIT_R1, JIT_R1,
			 -2 * sizeof(evalue_t) + offsetof(evalue_t, v.o));
		if (cdyn) {
		    jit_ldxi(JIT_R1, JIT_R1, voff);
		    voff = 0;
		}
		break;
	    default:
		abort();
	}
    }
    switch (kind) {
	case ii32:
	    switch (lcode) {
		case eop_noop:
		    maybe_reload_ireg32_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg(JIT_R1, voff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(JIT_R1, voff, type);
		    break;
		default:
		    abort();
	    }
	    switch (ccode) {
		case eop_lt:	jump = jit_blti(JIT_V1, data.s.l);	break;
		case eop_le:	jump = jit_blei(JIT_V1, data.s.l);	break;
		case eop_eq:	jump = jit_beqi(JIT_V1, data.s.l);	break;
		case eop_ge:	jump = jit_bgei(JIT_V1, data.s.l);	break;
		case eop_gt:	jump = jit_bgti(JIT_V1, data.s.l);	break;
		default:	jump = jit_bnei(JIT_V1, data.s.l);	break;
	    }
	    if (index >= 0)	jit_patch_at(jump, labels[index]);
	    else		record_forward_patch(jump, -index);
	    break;
	case ii64:		case iu64:
	    switch (lcode) {
		case eop_noop:
		    maybe_reload_extend_ireg_implicit(type);
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg(JIT_R1, voff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(JIT_R1, voff, type);
		    zero_sign_extend(type);
		    break;
		default:
		    abort();
	    }
	    if (kind == iu64) {
#  if __WORDSIZE == 32
		next = jit_bgei(JIT_V2, 0);
		store_ireg_implicit_rgz(0, JIT_V1, JIT_V2);
#  else
		next = jit_bgei(JIT_V1, 0);
		store_ireg_implicit_rgz(0, JIT_V1);
#  endif
		jit_ldxi(JIT_V1, JIT_V0, offsetof(ethread_t, esp));
		jit_calli(evm_push);
		emit_int_implicit(ast2, true);
		jit_prepare(jit_call_default);
		jit_pushargr(JIT_V1);
		switch (ccode) {
		    case eop_lt:	jit_finishi(evm_i_lt);		break;
		    case eop_le:	jit_finishi(evm_i_le);		break;
		    case eop_eq:	jit_finishi(evm_i_eq);		break;
		    case eop_ge:	jit_finishi(evm_i_ge);		break;
		    case eop_gt:	jit_finishi(evm_i_gt);		break;
		    default:		jit_finishi(evm_i_ne);		break;
		}
		jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
		load_ireg32_implicit();
		jump = jit_bnei(JIT_V1, 0);
		if (index >= 0)
		    jit_patch_at(jump, labels[index]);
		else
		    record_forward_patch(jump, -index);
		done = jit_jmpi();
		jit_patch(next);
	    }
#  if __WORDSIZE == 32
	    switch (ccode) {
		case eop_lt:
		    jump = jit_blti(JIT_V2, data.s.h);
		    temp = jit_bgti(JIT_V2, data.s.h);
		    if (index >= 0)	jit_patch_at(jump, labels[index]);
		    else		record_forward_patch(jump, -index);
		    jump = jit_blti_u(JIT_V1, data.s.l);
		    jit_patch(temp);
		    break;
		case eop_le:
		    jump = jit_blti(JIT_V2, data.s.h);
		    temp = jit_bgti(JIT_V2, data.s.h);
		    if (index >= 0)	jit_patch_at(jump, labels[index]);
		    else		record_forward_patch(jump, -index);
		    jump = jit_blei_u(JIT_V1, data.s.l);
		    jit_patch(temp);
		    break;
		case eop_eq:
		    temp = jit_bnei(JIT_V1, data.s.l);
		    jump = jit_beqi(JIT_V2, data.s.h);
		    jit_patch(temp);
		    break;
		case eop_ge:
		    jump = jit_bgti(JIT_V2, data.s.h);
		    temp = jit_blti(JIT_V2, data.s.h);
		    if (index >= 0)	jit_patch_at(jump, labels[index]);
		    else		record_forward_patch(jump, -index);
		    jump = jit_bgei_u(JIT_V1, data.s.l);
		    jit_patch(temp);
		    break;
		case eop_gt:
		    jump = jit_bgti(JIT_V2, data.s.h);
		    temp = jit_blti(JIT_V2, data.s.h);
		    if (index >= 0)	jit_patch_at(jump, labels[index]);
		    else		record_forward_patch(jump, -index);
		    jump = jit_bgti_u(JIT_V1, data.s.l);
		    jit_patch(temp);
		    break;
		default:
		    jump = jit_bnei(JIT_V1, data.s.l);
		    if (index >= 0)
			jit_patch_at(jump, labels[index]);
		    else
			record_forward_patch(jump, -index);
		    jump = jit_bnei(JIT_V2, data.s.h);
		    break;
	    }
#  else
	    switch (ccode) {
		case eop_lt:	jump = jit_blti(JIT_V1, data.L);	break;
		case eop_le:	jump = jit_blei(JIT_V1, data.L);	break;
		case eop_eq:	jump = jit_beqi(JIT_V1, data.L);	break;
		case eop_ge:	jump = jit_bgei(JIT_V1, data.L);	break;
		case eop_gt:	jump = jit_bgti(JIT_V1, data.L);	break;
		default:	jump = jit_bnei(JIT_V1, data.L);	break;
	    }
#  endif
	    if (index >= 0)	jit_patch_at(jump, labels[index]);
	    else		record_forward_patch(jump, -index);
	    if (kind == iu64)
		jit_patch(done);
	    break;
	case if32:
	    switch (lcode) {
		case eop_noop:
		    if (!(ejit_sync & ejit_sync_register))
			load_freg_implicit();
		    else if (!(ejit_sync & ejit_sync_float_ext))
			jit_extr_f_d(JIT_F0, JIT_F1);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_freg_type(JIT_R1, voff, t_float32);
		    jit_extr_f_d(JIT_F0, JIT_F1);
		    break;
		default:
		    abort();
	    }
	    goto float_cmp;
	case if64:
	    switch (lcode) {
		case eop_noop:
		    maybe_reload_freg_implicit();
		    break;
		case eop_ld:	case eop_ldt:
		case eop_lb:	case eop_lbt:	case eop_lc:
		    load_freg(JIT_R1, voff);
		    break;
		default:
		    abort();
	    }
	float_cmp:
	    data.F = data.L;
	    switch (ccode) {
		case eop_lt:	jump = jit_blti_d(JIT_F0, data.F);	break;
		case eop_le:	jump = jit_blei_d(JIT_F0, data.F);	break;
		case eop_eq:	jump = jit_beqi_d(JIT_F0, data.F);	break;
		case eop_ge:	jump = jit_bgei_d(JIT_F0, data.F);	break;
		case eop_gt:	jump = jit_bgti_d(JIT_F0, data.F);	break;
		default:	jump = jit_bnei_d(JIT_F0, data.F);	break;
	    }
	    if (index >= 0)	jit_patch_at(jump, labels[index]);
	    else		record_forward_patch(jump, -index);
	    break;
	default:
	    if (doint || doflt) {
		load = null;
		done = jit_forward();
		switch (lcode) {
		    case eop_noop:
			assert(ejit_sync & ejit_sync_implicit);
			jit_ldxi_i(JIT_R0, JIT_V0, toff);
			break;
		    case eop_lb:
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			break;
		    case eop_lc:
			assert(cdyn);
		    case eop_ld:
			assert(doint);
			load = jit_forward();
			next = jit_bnei(JIT_R1, 0);
			jit_movr(JIT_V1, JIT_R1);
#  if __WORDSIZE == 32
			jit_movr(JIT_V2, JIT_R1);
#  endif
			jump = jit_jmpi();
			jit_patch_at(jump, load);
			jit_patch(next);
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			next = null;
			break;
		    default:
			abort();
		}
	    }
	    else
		done = next = null;
	    if (doint) {
		next = jit_bnei(JIT_R0, t_int);
		switch (lcode) {
		    case eop_noop:
			maybe_reload_ireg_implicit();
			break;
		    case eop_ld:	case eop_lb:	case eop_lc:
			load_ireg(JIT_R1, voff);
			break;
		    default:
			abort();
		}
		if (load)
		    jit_link(load);
#  if __WORDSIZE == 32
		switch (ccode) {
		    case eop_lt:
			jump = jit_blti(JIT_V2, data.s.h);
			temp = jit_bgti(JIT_V2, data.s.h);
			if (index >= 0)	jit_patch_at(jump, labels[index]);
			else		record_forward_patch(jump, -index);
			jump = jit_blti_u(JIT_V1, data.s.l);
			jit_patch(temp);
			break;
		    case eop_le:
			jump = jit_blti(JIT_V2, data.s.h);
			temp = jit_bgti(JIT_V2, data.s.h);
			if (index >= 0)	jit_patch_at(jump, labels[index]);
			else		record_forward_patch(jump, -index);
			jump = jit_blei_u(JIT_V1, data.s.l);
			jit_patch(temp);
			break;
		    case eop_eq:
			temp = jit_bnei(JIT_V1, data.s.l);
			jump = jit_beqi(JIT_V2, data.s.h);
			jit_patch(temp);
			break;
		    case eop_ge:
			jump = jit_bgti(JIT_V2, data.s.h);
			temp = jit_blti(JIT_V2, data.s.h);
			if (index >= 0)	jit_patch_at(jump, labels[index]);
			else		record_forward_patch(jump, -index);
			jump = jit_bgei_u(JIT_V1, data.s.l);
			jit_patch(temp);
			break;
		    case eop_gt:
			jump = jit_bgti(JIT_V2, data.s.h);
			temp = jit_blti(JIT_V2, data.s.h);
			if (index >= 0)	jit_patch_at(jump, labels[index]);
			else		record_forward_patch(jump, -index);
			jump = jit_bgti_u(JIT_V1, data.s.l);
			jit_patch(temp);
			break;
		    default:
			jump = jit_bnei(JIT_V1, data.s.l);
			if (index >= 0)
			    jit_patch_at(jump, labels[index]);
			else
			    record_forward_patch(jump, -index);
			jump = jit_bnei(JIT_V2, data.s.h);
			break;
		}
#  else
		switch (ccode) {
		    case eop_lt:jump = jit_blti(JIT_V1, data.L);	break;
		    case eop_le:jump = jit_blei(JIT_V1, data.L);	break;
		    case eop_eq:jump = jit_beqi(JIT_V1, data.L);	break;
		    case eop_ge:jump = jit_bgei(JIT_V1, data.L);	break;
		    case eop_gt:jump = jit_bgti(JIT_V1, data.L);	break;
		    default:	jump = jit_bnei(JIT_V1, data.L);	break;
		}
#  endif
		if (index >= 0)		jit_patch_at(jump, labels[index]);
		else			record_forward_patch(jump, -index);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (doflt) {
		if (next)
		    jit_patch(next);
		next = jit_bnei(JIT_R0, t_float);
		switch (lcode) {
		    case eop_noop:
			maybe_reload_freg_implicit();
			break;
		    case eop_ld:	case eop_lb:	case eop_lc:
			load_freg(JIT_R1, voff);
			break;
		    default:
			abort();
		}
		switch (ccode) {
		    case eop_lt:jump = jit_blti_d(JIT_F0, data.L);	break;
		    case eop_le:jump = jit_blei_d(JIT_F0, data.L);	break;
		    case eop_eq:jump = jit_beqi_d(JIT_F0, data.L);	break;
		    case eop_ge:jump = jit_bgei_d(JIT_F0, data.L);	break;
		    case eop_gt:jump = jit_bgti_d(JIT_F0, data.L);	break;
		    default:	jump = jit_bnei_d(JIT_F0, data.L);	break;
		}
		if (index >= 0)		jit_patch_at(jump, labels[index]);
		else			record_forward_patch(jump, -index);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (next)
		jit_patch(next);
	    switch (lcode) {
		case eop_noop:						break;
		case eop_ld:	call_vi(evm_ld, soff);			break;
		case eop_lb:	call_vi(evm_lb, soff);			break;
		case eop_lc:	call_vii(evm_lc, soff, type);		break;
		default:	abort();
	    }
	    jit_ldxi(JIT_V1, JIT_V0, offsetof(ethread_t, esp));
	    jit_calli(evm_push);
	    emit_int_implicit(ast2, true);
	    jit_prepare(jit_call_default);
	    jit_pushargr(JIT_V1);
	    switch (ccode) {
		case eop_lt:	jit_finishi(evm_i_lt);			break;
		case eop_le:	jit_finishi(evm_i_le);			break;
		case eop_eq:	jit_finishi(evm_i_eq);			break;
		case eop_ge:	jit_finishi(evm_i_ge);			break;
		case eop_gt:	jit_finishi(evm_i_gt);			break;
		default:	jit_finishi(evm_i_ne);			break;
	    }
	    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
	    load_ireg32_implicit();
	    jump = jit_bnei(JIT_V1, 0);
	    if (index >= 0)	jit_patch_at(jump, labels[index]);
	    else		record_forward_patch(jump, -index);
	    if (done)
		jit_link(done);
	    break;
    }
    emit_clear();
}

static void
emit_load_push_int_addsub(east_list_t *ast0, east_list_t *ast1,
			  east_list_t *ast2, east_list_t *ast3)
{
    edata_t		 data;
    ecode_t		 load;
    eint32_t		 kind;
    eint32_t		 soff;
    eint32_t		 toff;
    eint32_t		 voff;
    etype_t		 type;
    jit_node_t		*done;
    jit_node_t		*fail;
    jit_node_t		*jump;
    jit_node_t		*next;
    jit_node_t		*over;

    data.L = immediate_int(east_node(ast2));
    if (ast0) {
	kind = ast0->itype;
	type = east_node(ast0)->csymbol.symbol->type;
	soff = east_node(ast0)->csymbol.symbol->offset;
	switch (load = east_node(ast0)->code) {
	    case eop_ld:	case eop_ldt:
		if (kind)
		    jit_ldi(JIT_R1, (jit_word_t)
			    (eint8_t *)eds + soff * sizeof(eobject_t));
		toff = -4;
		voff = 0;
		break;
	    case eop_lb:	case eop_lbt:
		if (kind)
		    jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
		toff = soff * sizeof(evalue_t) + offsetof(evalue_t, t);
		voff = soff * sizeof(evalue_t) + offsetof(evalue_t, v.o);
		break;
	    case eop_lc:
		if (kind) {
		    jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
		    /* pointer to 'this' */
		    jit_ldxi(JIT_R1, JIT_R1,
			     -2 * sizeof(evalue_t) + offsetof(evalue_t, v.o));
		}
		toff = -4;
		voff = soff;
		break;
	    default:
		abort();
	}
    }
    else {
	soff = 0;
	load = eop_noop;
	kind = type = ast1->rtype;
	toff = offsetof(ethread_t, r0) + offsetof(evalue_t, t);
	voff = offsetof(ethread_t, r0) + offsetof(evalue_t, v.o);
    }
    switch (kind) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    kind = li32;		break;
	case t_uint32:	case t_int:
	    kind = li64;		break;
	case t_uint:
	    kind = lu64;		break;
	case t_exact:
	    kind = lint;		break;
	case t_float32:
	    kind = lf32;		break;
	case t_float:
	    kind = lf64;		break;
	case t_inexact:
	    kind = lrel;		break;
	case t_dynamic:
	    kind = lint|lrel;		break;
	default:
	    kind = 0;			break;
    }
    if (east_node(ast2)->code == eop_int)
	kind |= ri32;
    else
	kind |= ri64;
    switch (ast3->itype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    kind |= ii32;		break;
	case t_int64:
	    kind |= ii64;		break;
	case t_float64:
	    kind |= if64;		break;
	case t_exact:
	    kind |= iint;		break;
	case t_inexact:
	    kind |= irel;		break;
	case t_dynamic:
	    kind |= iint|irel;		break;
	default:
	    break;
    }
    switch (kind) {
	case li32|ri32|ii32:
	    switch (load) {
		case eop_noop:
		    maybe_reload_ireg32_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg(JIT_R1, voff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(JIT_R1, voff, ast0->itype);
		    break;
		default:
		    abort();
	    }
	    if (east_node(ast3)->code == eop_add)
		jit_addi(JIT_V1, JIT_V1, data.s.l);
	    else
		jit_subi(JIT_V1, JIT_V1, data.s.l);
	    ejit_sync = ejit_sync_register;
	    break;
	case li32|ri32|ii64:	case li32|ri64|ii64:
	case li64|ri32|ii64:	case li64|ri64|ii64:
	    switch (load) {
		case eop_noop:
		    maybe_reload_extend_ireg_implicit(ast1->itype);
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg(JIT_R1, voff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(JIT_R1, voff, ast0->itype);
		    zero_sign_extend(ast0->itype);
		    break;
		default:
		    abort();
	    }
#  if __WORDSIZE == 32
	    if (east_node(ast3)->code == eop_add) {
		jit_addci(JIT_V1, JIT_V1, data.s.l);
		jit_addxi(JIT_V2, JIT_V2, data.s.h);
	    }
	    else {
		jit_subci(JIT_V1, JIT_V1, data.s.l);
		jit_subxi(JIT_V2, JIT_V2, data.s.h);
	    }
#  else
	    if (east_node(ast3)->code == eop_add)
		jit_addi(JIT_V1, JIT_V1, data.s.l);
	    else
		jit_subi(JIT_V1, JIT_V1, data.s.l);
#  endif
	    ejit_sync = ejit_sync_register|ejit_sync_int_ext;
	    break;
	case li32|ri64|iint:
	case li64|ri32|iint:	case li64|ri64|iint:
	case lu64|ri32|iint:	case lu64|ri64|iint:
	    switch (load) {
		case eop_noop:
		    maybe_reload_extend_ireg_implicit(ast1->itype);
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg(JIT_R1, voff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(JIT_R1, voff, ast0->itype);
		    zero_sign_extend(ast0->itype);
		    break;
		default:
		    abort();
	    }
	    next = null;
	    done = jit_forward();
	    over = jit_forward();
	    if (kind & lu64) {
#  if __WORDSIZE == 32
		next = jit_bgei(JIT_V2, 0);
		store_ireg_implicit_rgz(0, JIT_V1, JIT_V2);
#  else
		next = jit_bgei(JIT_V1, 0);
		store_ireg_implicit_rgz(0, JIT_V1);
#  endif
	    }
	    if (load == eop_noop) {
		/* if cannot reload, otherwise, reload on overflow fallback */
		if (!(ejit_sync & ejit_sync_implicit)) {
		    assert(ejit_sync & ejit_sync_register);
		    store_ireg_implicit(true);
		}
	    }
#  if __WORDSIZE == 32
	    jit_movr(JIT_R2, JIT_V1);
	    if (east_node(ast3)->code == eop_add) {
		jit_addi(JIT_V1, JIT_V1, data.s.l);
		jit_ltr_u(JIT_R0, JIT_V1, JIT_R2);
	    }
	    else {
		jit_subi(JIT_V1, JIT_V1, data.s.l);
		jit_gtr_u(JIT_R0, JIT_V1, JIT_R2);
	    }
	    jit_movi(JIT_R2, data.s.h);
	    jump = jit_boaddr(JIT_R2, JIT_R0);
	    jit_patch_at(jump, over);
	    if (east_node(ast3)->code == eop_add)
		jump = jit_boaddr(JIT_V2, JIT_R2);
	    else
		jump = jit_bosubr(JIT_V2, JIT_R2);
#  else
	    if (east_node(ast3)->code == eop_add)
		jump = jit_boaddi(JIT_V1, data.L);
	    else
		jump = jit_bosubi(JIT_V1, data.L);
#  endif
	    jit_patch_at(jump, over);
	    store_ireg_implicit(load != eop_noop || (kind & lu64) ||
				!(ejit_sync & ejit_sync_implicit));
	    jump = jit_jmpi();
	    jit_patch_at(jump, done);
	    jit_link(over);
	    switch (load) {
		case eop_noop:					break;
		case eop_ld:	call_vi(evm_ld, soff);		break;
		case eop_ldt:	call_vii(evm_ldt, soff, type);	break;
		case eop_lb:	call_vi(evm_lb, soff);		break;
		case eop_lbt:	call_vii(evm_lbt, soff, type);	break;
		case eop_lc:	call_vii(evm_lc, soff, type);	break;
		default:
		    abort();
	    }
	    if (next)
		/* uint64_t to mpz conversion done */
		jit_patch(next);
	    jit_ldxi(JIT_V1, JIT_V0, offsetof(ethread_t, esp));
	    jit_calli(evm_push);
	    emit_int_implicit(ast2, load != eop_noop || (kind & lu64) ||
			      !(ejit_sync & ejit_sync_implicit));
	    jit_prepare(jit_call_default);
	    jit_pushargr(JIT_V1);
	    if (east_node(ast3)->code == eop_add)
		jit_finishi(evm_i_add);
	    else
		jit_finishi(evm_i_sub);
	    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
	    jit_ldxi_i(JIT_R0, JIT_V0,
		       offsetof(ethread_t, r0) + offsetof(evalue_t, t));
	    jump = jit_bnei(JIT_R0, t_int);
	    jit_patch_at(jump, done);
	    load_ireg_implicit();
	    jit_link(done);
	    ejit_sync = ejit_sync_register|ejit_sync_dynamic|
			ejit_sync_implicit|ejit_sync_int_ext;
	    break;
	case lf32|ri32|if64:		case lf32|ri64|if64:
	    switch (load) {
		case eop_noop:
		    if (!(ejit_sync & ejit_sync_register))
			load_freg_implicit();
		    else if (!(ejit_sync & ejit_sync_float_ext))
			jit_extr_f_d(JIT_F0, JIT_F1);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_freg_type(JIT_R1, voff, t_float32);
		    jit_extr_f_d(JIT_F0, JIT_F1);
		    break;
		default:
		    abort();
	    }
	    if (east_node(ast3)->code == eop_add)
		jit_addi_d(JIT_F0, JIT_F0, data.L);
	    else
		jit_subi_d(JIT_F0, JIT_F0, data.L);
	    ejit_sync = ejit_sync_register;
	    break;
	case lf64|ri32|if64:		case lf64|ri64|if64:
	    switch (load) {
		case eop_noop:
		    maybe_reload_freg_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_freg(JIT_R1, voff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_freg_type(JIT_R1, voff, t_float);
		    break;
		default:
		    abort();
	    }
	    if (east_node(ast3)->code == eop_add)
		jit_addi_d(JIT_F0, JIT_F0, data.L);
	    else
		jit_subi_d(JIT_F0, JIT_F0, data.L);
	    ejit_sync = ejit_sync_register;
	    break;
	default:
	    fail = over = null;
	    if (kind & (lint|lrel)) {
		done = jit_forward();
		switch (load) {
		    case eop_noop:
			assert(ejit_sync & ejit_sync_implicit);
			jit_ldxi_i(JIT_R0, JIT_V0, toff);
			break;
		    case eop_ld:
			fail = jit_beqi(JIT_R1, 0);
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			break;
		    case eop_lb:
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			break;
		    case eop_lc:
			jit_ldxi(JIT_R1, JIT_R1, voff);
			fail = jit_beqi(JIT_R1, 0);
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			voff = 0;
			break;
		    default:
			abort();
		}
	    }
	    else
		done = next = null;
	    if (kind & lint) {
		next = jit_bnei(JIT_R0, t_int);
		switch (load) {
		    case eop_noop:
			load_ireg_implicit();
			break;
		    case eop_ld:	case eop_lb:	case eop_lc:
			load_ireg(JIT_R1, voff);
			break;
		    default:
			abort();
		}
		over = jit_forward();
#  if __WORDSIZE == 32
		jit_movr(JIT_R2, JIT_V1);
		if (east_node(ast3)->code == eop_add) {
		    jit_addi(JIT_V1, JIT_V1, data.s.l);
		    jit_ltr_u(JIT_R0, JIT_V1, JIT_R2);
		}
		else {
		    jit_subi(JIT_V1, JIT_V1, data.s.l);
		    jit_gtr_u(JIT_R0, JIT_V1, JIT_R2);
		}
		jit_movi(JIT_R2, data.s.h);
		jump = jit_boaddr(JIT_R2, JIT_R0);
		jit_patch_at(jump, over);
		if (east_node(ast3)->code == eop_add)
		    jump = jit_boaddr(JIT_V2, JIT_R2);
		else
		    jump = jit_bosubr(JIT_V2, JIT_R2);
#  else
		if (east_node(ast3)->code == eop_add)
		    jump = jit_boaddi(JIT_V1, data.L);
		else
		    jump = jit_bosubi(JIT_V1, data.L);
#  endif
		jit_patch_at(jump, over);
		store_ireg_implicit(load != eop_noop);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (kind & lrel) {
		if (next)
		    jit_patch(next);
		next = jit_bnei(JIT_R0, t_float);
		switch (load) {
		    case eop_noop:
			load_freg_implicit();
			break;
		    case eop_ld:	case eop_lb:	case eop_lc:
			load_freg(JIT_R1, voff);
			break;
		    default:
			abort();
		}
		if (east_node(ast3)->code == eop_add)
		    jit_addi_d(JIT_F0, JIT_F0, data.L);
		else
		    jit_subi_d(JIT_F0, JIT_F0, data.L);
		store_freg_implicit(true);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (over)
		jit_link(over);
	    if (next)
		jit_patch(next);
	    if (fail)
		jit_patch(fail);
	    switch (load) {
		case eop_noop:					break;
		case eop_ld:	call_vi(evm_ld, soff);		break;
		case eop_lb:	call_vi(evm_lb, soff);		break;
		case eop_lc:	call_vii(evm_lc, soff, type);	break;
		default:	abort();
	    }
	    jit_ldxi(JIT_V1, JIT_V0, offsetof(ethread_t, esp));
	    jit_calli(evm_push);
	    emit_int_implicit(ast2, true);
	    jit_prepare(jit_call_default);
	    jit_pushargr(JIT_V1);
	    if (east_node(ast3)->code == eop_add)
		jit_finishi(evm_i_add);
	    else
		jit_finishi(evm_i_sub);
	    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
	    next = jump = null;
	    if (kind & (iint|irel))
		jit_ldxi_i(JIT_R0, JIT_V0,
			   offsetof(ethread_t, r0) + offsetof(evalue_t, t));
	    if (kind & iint) {
		next = jit_bnei(JIT_R0, t_int);
		load_ireg_implicit();
		jump = jit_jmpi();
	    }
	    else
		DEBUG_IMPLICIT_TYPE_INT();
	    if (kind & irel) {
		if (next)
		    jit_patch(next);
		next = jit_bnei(JIT_R0, t_float);
		load_freg_implicit();
	    }
	    else
		DEBUG_IMPLICIT_TYPE_FLOAT();
	    if (jump)
		jit_patch(jump);
	    if (next)
		jit_patch(next);
	    if (done)
		jit_link(done);
	    ejit_sync = ejit_sync_register|ejit_sync_dynamic|
			ejit_sync_implicit|ejit_sync_int_ext;
	    break;
    }
    ejit_type = ast3->itype;
}

static void
emit_load_push_float_cmp(east_list_t *ast0, east_list_t *ast1,
			 east_list_t *ast2, east_list_t *ast3)
{
    jit_node_t		*done;
    jit_node_t		*jump;
    jit_node_t		*load;
    jit_node_t		*next;
    ebool_t		 cdyn;
    edata_t		 data;
    eint32_t		 kind;
    ecode_t		 code;
    eint32_t		 soff;
    eint32_t		 toff;
    eint32_t		 voff;
    etype_t		 type;
    ebool_t		 doint;
    ebool_t		 doflt;

    cdyn = false;
    data.F = immediate_float(east_node(ast2));
    if (ast0) {
	kind = ast0->itype;
	soff = east_node(ast0)->csymbol.symbol->offset;
	type = east_node(ast0)->csymbol.symbol->type;
	switch (code = east_node(ast0)->code) {
	    case eop_ld:	case eop_ldt:
		toff = -4;
		voff = 0;
		break;
	    case eop_lb:	case eop_lbt:
		toff = soff * sizeof(evalue_t) + offsetof(evalue_t, t);
		voff = soff * sizeof(evalue_t) + offsetof(evalue_t, v.o);
		break;
	    case eop_lc:
		toff = -4;
		voff = soff;
		cdyn = type == t_void || type > elast_basic_type;
		break;
	    default:
		abort();
	}
    }
    else {
	soff = 0;
	code = eop_noop;
	kind = type = ast1->rtype;
	toff = offsetof(ethread_t, r0) + offsetof(evalue_t, t);
	voff = offsetof(ethread_t, r0) + offsetof(evalue_t, v.o);
    }
    switch (kind) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    kind = ii32;		break;
	case t_uint32:	case t_int:
	    kind = ii64;		break;
	case t_uint:
	    kind = iu64;		break;
	case t_exact:
	    kind = iint;		break;
	case t_float32:
	    kind = if32;		break;
	case t_float:
	    kind = if64;		break;
	case t_inexact:
	    kind = irel;		break;
	case t_dynamic:
	    kind = iint|irel;		break;
	default:
	    kind = 0;			break;
    }
    doint = !!(kind & (ii32|ii64|iu64|iint));
    doflt = !!(kind & (if32|if64|irel));
    if (doint || doflt) {
	switch (code) {
	    case eop_noop:
		break;
	    case eop_ld:	case eop_ldt:
		jit_ldi(JIT_R1, (jit_word_t)
			(eint8_t *)eds + soff * sizeof(eobject_t));
		break;
	    case eop_lb:	case eop_lbt:
		jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
		break;
	    case eop_lc:
		jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
		/* pointer to 'this' */
		jit_ldxi(JIT_R1, JIT_R1,
			 -2 * sizeof(evalue_t) + offsetof(evalue_t, v.o));
		if (cdyn) {
		    jit_ldxi(JIT_R1, JIT_R1, voff);
		    voff = 0;
		}
		break;
	    default:
		abort();
	}
    }
    switch (kind) {
	case ii32:
	    switch (code) {
		case eop_noop:
		    maybe_reload_ireg32_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg(JIT_R1, voff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(JIT_R1, voff, type);
		    break;
		default:
		    abort();
	    }
	    jit_extr_d(JIT_F0, JIT_V1);
	    goto float_cmp;
	case ii64:	case iu64:
	    switch (code) {
		case eop_noop:
		    maybe_reload_extend_ireg_implicit(type);
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg(JIT_R1, voff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(JIT_R1, voff, type);
		    zero_sign_extend(type);
		    break;
		default:
		    abort();
	    }
#  if __WORDSIZE == 32
	    if (kind == iu64) {
		jump = jit_bgei(JIT_V2, 0);
		store_ireg_implicit_rgz(RGZ_ptr_to_v1, JIT_V1, JIT_V2);
		jit_prepare(jit_call_default);
		jit_pushargr(JIT_V1);
		jit_finishi(mpz_get_d);
		jit_retval_d(JIT_F0);
		next = jit_jmpi();
		jit_patch(jump);
	    }
	    store_ireg_implicit(code != eop_noop ||
				!(ejit_sync & ejit_sync_implicit));
	    jit_addi(JIT_R0, JIT_V0,
		     offsetof(ethread_t, r0) + offsetof(evalue_t, v.d));
	    jit_prepare(jit_call_default);
	    jit_pushargr(JIT_R0);
	    jit_finishi(evm_store_float64);
	    load_freg_implicit();
	    if (kind == iu64)
		jit_patch(next);
#  else
	    if (kind == iu64) {
		jump = jit_bgei(JIT_V1, 0);
		store_ireg_implicit_rgz(RGZ_ptr_to_v1, JIT_V1);
		jit_prepare(jit_call_default);
		jit_pushargr(JIT_V1);
		jit_finishi(mpz_get_d);
		jit_retval_d(JIT_F0);
		next = jit_jmpi();
		jit_patch(jump);
	    }
	    jit_extr_d(JIT_F0, JIT_V1);
	    if (kind == iu64)
		jit_patch(next);
#  endif
	    goto float_cmp;
	case if32:
	    switch (code) {
		case eop_noop:
		    if (!(ejit_sync & ejit_sync_register))
			load_freg_implicit();
		    else if (!(ejit_sync & ejit_sync_float_ext))
			jit_extr_f_d(JIT_F0, JIT_F1);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_freg_type(JIT_R1, voff, t_float32);
		    jit_extr_f_d(JIT_F0, JIT_F1);
		    break;
		default:
		    abort();
	    }
	    goto float_cmp;
	case if64:
	    switch (code) {
		case eop_noop:
		    maybe_reload_freg_implicit();
		    break;
		case eop_ld:	case eop_ldt:
		case eop_lb:	case eop_lbt:	case eop_lc:
		    load_freg(JIT_R1, voff);
		    break;
		default:
		    abort();
	    }
	float_cmp:
	    switch (east_node(ast3)->code) {
		case eop_lt:	jit_lti_d(JIT_V1, JIT_F0, data.F);	break;
		case eop_le:	jit_lei_d(JIT_V1, JIT_F0, data.F);	break;
		case eop_eq:	jit_eqi_d(JIT_V1, JIT_F0, data.F);	break;
		case eop_ge:	jit_gei_d(JIT_V1, JIT_F0, data.F);	break;
		case eop_gt:	jit_gti_d(JIT_V1, JIT_F0, data.F);	break;
		default:	jit_nei_d(JIT_V1, JIT_F0, data.F);	break;
	    }
	    ejit_sync = ejit_sync_register;
	    break;
	default:
	    if (doint || doflt) {
		load = jit_forward();
		done = jit_forward();
		switch (code) {
		    case eop_noop:
			assert(ejit_sync & ejit_sync_implicit);
			jit_ldxi_i(JIT_R0, JIT_V0, toff);
			break;
		    case eop_lb:
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			break;
		    case eop_lc:
			assert(cdyn);
		    case eop_ld:
			next = jit_bnei(JIT_R1, 0);
			jit_movi_d(JIT_F0, 0.0);
			jump = jit_jmpi();
			jit_patch_at(jump, load);
			jit_patch(next);
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			break;
		    default:
			abort();
		}
		next = null;
	    }
	    else
		done = next = null;
	    if (doint) {
		next = jit_bnei(JIT_R0, t_int);
		if (code == eop_noop)
		    maybe_reload_ireg_implicit();
		else
		    load_ireg(JIT_R1, voff);
#  if __WORDSIZE == 32
		if (code != eop_noop)
		    store_ireg_implicit(true);
		jit_addi(JIT_R0, JIT_V0,
			 offsetof(ethread_t, r0) + offsetof(evalue_t, v.d));
		jit_prepare(jit_call_default);
		jit_pushargr(JIT_R0);
		jit_finishi(evm_store_float64);
		load_freg_implicit();
#  else
		jit_extr_d(JIT_F0, JIT_V1);
#  endif
		if (doflt) {
		    jump = jit_jmpi();
		    jit_patch_at(jump, load);
		}
	    }
	    if (doint || doflt) {
		if (doflt) {
		    if (next)
			jit_patch(next);
		    next = jit_bnei(JIT_R0, t_float);
		    if (code == eop_noop)
			maybe_reload_freg_implicit();
		    else
			load_freg(JIT_R1, voff);
		}
		if (load)
		    jit_link(load);
		switch (east_node(ast3)->code) {
		    case eop_lt:jit_lti_d(JIT_V1, JIT_F0, data.F);	break;
		    case eop_le:jit_lei_d(JIT_V1, JIT_F0, data.F);	break;
		    case eop_eq:jit_eqi_d(JIT_V1, JIT_F0, data.F);	break;
		    case eop_ge:jit_gei_d(JIT_V1, JIT_F0, data.F);	break;
		    case eop_gt:jit_gti_d(JIT_V1, JIT_F0, data.F);	break;
		    default:	jit_nei_d(JIT_V1, JIT_F0, data.F);	break;
		}
		store_ireg_implicit(true);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (next)
		jit_patch(next);
	    switch (code) {
		case eop_noop:
		    break;
		case eop_ld:
		    call_vi(evm_ld, soff);
		    break;
		case eop_lb:
		    call_vi(evm_lb, soff);
		    break;
		case eop_lc:
		    call_vii(evm_lc, soff,
			     east_node(ast0)->csymbol.symbol->type);
		    break;
		default:
		    abort();
	    }
	    jit_ldxi(JIT_V1, JIT_V0, offsetof(ethread_t, esp));
	    jit_calli(evm_push);
	    jit_movi_d(JIT_F0, data.F);
	    store_freg_implicit(true);
	    jit_prepare(jit_call_default);
	    jit_pushargr(JIT_V1);
	    switch (east_node(ast3)->code) {
		case eop_lt:	jit_finishi(evm_d_lt);			break;
		case eop_le:	jit_finishi(evm_d_le);			break;
		case eop_eq:	jit_finishi(evm_d_eq);			break;
		case eop_ge:	jit_finishi(evm_d_ge);			break;
		case eop_gt:	jit_finishi(evm_d_gt);			break;
		default:	jit_finishi(evm_d_ne);			break;
	    }
	    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
	    load_ireg32_implicit();
#  if __WORDSIZE == 32
	    jit_movi(JIT_V2, 0);
#  endif
	    if (done)
		jit_link(done);
	    ejit_sync = ejit_sync_register|ejit_sync_implicit|ejit_sync_int_ext;
	    break;
    }
    ejit_type = ast3->itype;
}

static void
emit_load_push_float_cmp_jmp(east_list_t *ast0, east_list_t *ast1,
			     east_list_t *ast2, east_list_t *ast3,
			     east_list_t *ast4)
{
    jit_node_t		*done;
    jit_node_t		*jump;
    jit_node_t		*load;
    jit_node_t		*next;
    ebool_t		 cdyn;
    edata_t		 data;
    eint32_t		 kind;
    eint32_t		 soff;
    eint32_t		 toff;
    eint32_t		 voff;
    etype_t		 type;
    ecode_t		 ccode;
    ecode_t		 lcode;
    ebool_t		 doint;
    ebool_t		 doflt;
    elabel_t		*label;
    eword_t		 index;

    if (east_node(ast4)->code == eop_jt)
	ccode = east_node(ast3)->code;
    else {
	switch (east_node(ast3)->code) {
	    case eop_lt:	ccode = eop_ge;		break;
	    case eop_le:	ccode = eop_gt;		break;
	    case eop_eq:	ccode = eop_ne;		break;
	    case eop_ge:	ccode = eop_lt;		break;
	    case eop_gt:	ccode = eop_le;		break;
	    default:		ccode = eop_eq;		break;
	}
    }
    label = east_node(ast4)->clabel.label;
    if (label->value == null)
	allocate_forward_label(label);
    index = eget_fixnum(label->value);
    data.F = immediate_float(east_node(ast2));
    cdyn = false;
    if (ast0) {
	kind = ast0->itype;
	soff = east_node(ast0)->csymbol.symbol->offset;
	type = east_node(ast0)->csymbol.symbol->type;
	switch (lcode = east_node(ast0)->code) {
	    case eop_ld:	case eop_ldt:
		toff = -4;
		voff = 0;
		break;
	    case eop_lb:	case eop_lbt:
		toff = soff * sizeof(evalue_t) + offsetof(evalue_t, t);
		voff = soff * sizeof(evalue_t) + offsetof(evalue_t, v.o);
		break;
	    case eop_lc:
		toff = -4;
		voff = soff;
		cdyn = type == t_void || type > elast_basic_type;
		break;
	    default:
		abort();
	}
    }
    else {
	soff = 0;
	lcode = eop_noop;
	type = kind = ast1->rtype;
	toff = offsetof(ethread_t, r0) + offsetof(evalue_t, t);
	voff = offsetof(ethread_t, r0) + offsetof(evalue_t, v.o);
    }
    switch (kind) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    kind = ii32;		break;
	case t_uint32:	case t_int:
	    kind = ii64;		break;
	case t_uint:
	    kind = iu64;		break;
	case t_exact:
	    kind = iint;		break;
	case t_float32:
	    kind = if32;		break;
	case t_float:
	    kind = if64;		break;
	case t_inexact:
	    kind = irel;		break;
	case t_dynamic:
	    kind = iint|irel;		break;
	default:
	    kind = 0;			break;
    }
    doint = !!(kind & (ii32|ii64|iu64|iint));
    doflt = !!(kind & (if32|if64|irel));
    if (doint || doflt) {
	switch (lcode) {
	    case eop_noop:
		break;
	    case eop_ld:	case eop_ldt:
		jit_ldi(JIT_R1, (jit_word_t)
			(eint8_t *)eds + soff * sizeof(eobject_t));
		break;
	    case eop_lb:	case eop_lbt:
		jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
		break;
	    case eop_lc:
		jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
		/* pointer to 'this' */
		jit_ldxi(JIT_R1, JIT_R1,
			 -2 * sizeof(evalue_t) + offsetof(evalue_t, v.o));
		if (cdyn) {
		    jit_ldxi(JIT_R1, JIT_R1, voff);
		    voff = 0;
		}
		break;
	    default:
		abort();
	}
    }
    switch (kind) {
	case ii32:
	    switch (lcode) {
		case eop_noop:
		    maybe_reload_ireg32_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg(JIT_R1, voff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(JIT_R1, voff, type);
		    break;
		default:
		    abort();
	    }
	    jit_extr_d(JIT_F0, JIT_V1);
	    goto float_cmp;
	case ii64:	case iu64:
	    switch (lcode) {
		case eop_noop:
		    maybe_reload_extend_ireg_implicit(type);
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg(JIT_R1, voff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(JIT_R1, voff, type);
		    zero_sign_extend(type);
		    break;
		default:
		    abort();
	    }
#  if __WORDSIZE == 32
	    if (kind == iu64) {
		jump = jit_bgei(JIT_V2, 0);
		store_ireg_implicit_rgz(RGZ_ptr_to_v1, JIT_V1, JIT_V2);
		jit_prepare(jit_call_default);
		jit_pushargr(JIT_V1);
		jit_finishi(mpz_get_d);
		jit_retval_d(JIT_F0);
		next = jit_jmpi();
		jit_patch(jump);
	    }
	    store_ireg_implicit(lcode != eop_noop ||
				!(ejit_sync & ejit_sync_implicit));
	    jit_addi(JIT_R0, JIT_V0,
		     offsetof(ethread_t, r0) + offsetof(evalue_t, v.d));
	    jit_prepare(jit_call_default);
	    jit_pushargr(JIT_R0);
	    jit_finishi(evm_store_float64);
	    load_freg_implicit();
	    if (kind == iu64)
		jit_patch(next);
#  else
	    if (kind == iu64) {
		jump = jit_bgei(JIT_V1, 0);
		store_ireg_implicit_rgz(RGZ_ptr_to_v1, JIT_V1);
		jit_prepare(jit_call_default);
		jit_pushargr(JIT_V1);
		jit_finishi(mpz_get_d);
		jit_retval_d(JIT_F0);
		next = jit_jmpi();
		jit_patch(jump);
	    }
	    jit_extr_d(JIT_F0, JIT_V1);
	    if (kind == iu64)
		jit_patch(next);
#  endif
	    goto float_cmp;
	case if32:
	    switch (lcode) {
		case eop_noop:
		    if (!(ejit_sync & ejit_sync_register))
			load_freg_implicit();
		    else if (!(ejit_sync & ejit_sync_float_ext))
			jit_extr_f_d(JIT_F0, JIT_F1);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_freg_type(JIT_R1, voff, t_float32);
		    jit_extr_f_d(JIT_F0, JIT_F1);
		    break;
		default:
		    abort();
	    }
	    goto float_cmp;
	case if64:
	    switch (lcode) {
		case eop_noop:
		    maybe_reload_freg_implicit();
		    break;
		case eop_ld:	case eop_ldt:
		case eop_lb:	case eop_lbt:	case eop_lc:
		    load_freg(JIT_R1, voff);
		    break;
		default:
		    abort();
	    }
	float_cmp:
	    switch (ccode) {
		case eop_lt:	jump = jit_blti_d(JIT_F0, data.F);	break;
		case eop_le:	jump = jit_blei_d(JIT_F0, data.F);	break;
		case eop_eq:	jump = jit_beqi_d(JIT_F0, data.F);	break;
		case eop_ge:	jump = jit_bgei_d(JIT_F0, data.F);	break;
		case eop_gt:	jump = jit_bgti_d(JIT_F0, data.F);	break;
		default:	jump = jit_bnei_d(JIT_F0, data.F);	break;
	    }
	    if (index >= 0)	jit_patch_at(jump, labels[index]);
	    else		record_forward_patch(jump, -index);
	    break;
	default:
	    if (doint || doflt) {
		load = jit_forward();
		done = jit_forward();
		switch (lcode) {
		    case eop_noop:
			assert(ejit_sync & ejit_sync_implicit);
			jit_ldxi_i(JIT_R0, JIT_V0, toff);
			break;
		    case eop_lb:
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			break;
		    case eop_lc:
			assert(cdyn);
		    case eop_ld:
			next = jit_bnei(JIT_R1, 0);
			jit_movi_d(JIT_F0, 0.0);
			jump = jit_jmpi();
			jit_patch_at(jump, load);
			jit_patch(next);
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			break;
		    default:
			abort();
		}
		next = null;
	    }
	    else
		done = next = null;
	    if (doint) {
		next = jit_bnei(JIT_R0, t_int);
		if (lcode == eop_noop)
		    maybe_reload_ireg_implicit();
		else
		    load_ireg(JIT_R1, voff);
#  if __WORDSIZE == 32
		if (lcode != eop_noop)
		    store_ireg_implicit(true);
		jit_addi(JIT_R0, JIT_V0,
			 offsetof(ethread_t, r0) + offsetof(evalue_t, v.d));
		jit_prepare(jit_call_default);
		jit_pushargr(JIT_R0);
		jit_finishi(evm_store_float64);
		load_freg_implicit();
#  else
		jit_extr_d(JIT_F0, JIT_V1);
#  endif
		if (doflt) {
		    jump = jit_jmpi();
		    jit_patch_at(jump, load);
		}
	    }
	    if (doint || doflt) {
		if (doflt) {
		    if (next)
			jit_patch(next);
		    next = jit_bnei(JIT_R0, t_float);
		    if (lcode == eop_noop)
			maybe_reload_freg_implicit();
		    else
			load_freg(JIT_R1, voff);
		}
		if (load)
		    jit_link(load);
		switch (ccode) {
		    case eop_lt:jump = jit_blti_d(JIT_F0, data.F);	break;
		    case eop_le:jump = jit_blei_d(JIT_F0, data.F);	break;
		    case eop_eq:jump = jit_beqi_d(JIT_F0, data.F);	break;
		    case eop_ge:jump = jit_bgei_d(JIT_F0, data.F);	break;
		    case eop_gt:jump = jit_bgti_d(JIT_F0, data.F);	break;
		    default:	jump = jit_bnei_d(JIT_F0, data.F);	break;
		}
		if (index >= 0)		jit_patch_at(jump, labels[index]);
		else			record_forward_patch(jump, -index);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (next)
		jit_patch(next);
	    switch (lcode) {
		case eop_noop:
		    break;
		case eop_ld:
		    call_vi(evm_ld, soff);
		    break;
		case eop_lb:
		    call_vi(evm_lb, soff);
		    break;
		case eop_lc:
		    call_vii(evm_lc, soff,
			     east_node(ast0)->csymbol.symbol->type);
		    break;
		default:
		    abort();
	    }
	    jit_ldxi(JIT_V1, JIT_V0, offsetof(ethread_t, esp));
	    jit_calli(evm_push);
	    jit_movi_d(JIT_F0, data.F);
	    store_freg_implicit(true);
	    jit_prepare(jit_call_default);
	    jit_pushargr(JIT_V1);
	    switch (ccode) {
		case eop_lt:	jit_finishi(evm_d_lt);			break;
		case eop_le:	jit_finishi(evm_d_le);			break;
		case eop_eq:	jit_finishi(evm_d_eq);			break;
		case eop_ge:	jit_finishi(evm_d_ge);			break;
		case eop_gt:	jit_finishi(evm_d_gt);			break;
		default:	jit_finishi(evm_d_ne);			break;
	    }
	    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
	    load_ireg32_implicit();
	    jump = jit_bnei(JIT_V1, 0);
	    if (index >= 0)	jit_patch_at(jump, labels[index]);
	    else		record_forward_patch(jump, -index);
	    if (done)
		jit_link(done);
	    break;
    }
    emit_clear();
}

static void
emit_load_push_load_cmp(east_list_t *ast0, east_list_t *ast1,
			east_list_t *ast2, east_list_t *ast3)
{
    ebool_t		 same;
    jit_node_t		*done;
#  if  __WORDSIZE == 32
    jit_node_t		*temp;
#  endif
    jit_node_t		*fail,  *jext;
    jit_node_t		*jcvt,  *jump;
    jit_node_t		*lnext, *rnext;
    ecode_t		 lcode,  rcode;
    etype_t		 ltype,  rtype;
    eint32_t		 lsoff,  rsoff;
    eint32_t		 ltoff,  rtoff;
    eint32_t		 lvoff,  rvoff;
    eint32_t		 lcdyn,  rcdyn;
    jit_int32_t		 lbase,  rbase;
    ebool_t		 doint,  doflt;
    eint32_t		 lkind,  rkind;

    lbase = rbase = JIT_R1;
    done = fail = lnext = rnext = null;
    doint = doflt = lcdyn = rcdyn = false;
    if (ast0) {
	lkind = ast0->itype;
	ltype = east_node(ast0)->csymbol.symbol->type;
	lsoff = east_node(ast0)->csymbol.symbol->offset;
	switch (lcode = east_node(ast0)->code) {
	    case eop_ld:	case eop_ldt:
		ltoff = -4;	lvoff = 0;
		break;
	    case eop_lb:	case eop_lbt:
		ltoff = lsoff * sizeof(evalue_t) + offsetof(evalue_t, t);
		lvoff = lsoff * sizeof(evalue_t) + offsetof(evalue_t, v.o);
		break;
	    case eop_lc:
		ltoff = -4;	lvoff = lsoff;
		lcdyn = ltype == t_void || ltype > elast_basic_type;
		break;
	    default:
		abort();
	}
    }
    else {
	lkind = ltype = ast1->rtype;
	lsoff = 0;
	lcode = eop_noop;
	ltoff = offsetof(ethread_t, r0) + offsetof(evalue_t, t);
	lvoff = offsetof(ethread_t, r0) + offsetof(evalue_t, v.o);
    }
    switch (lkind) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    lkind = li32;		break;
	case t_uint32:	case t_int:
	    lkind = li64;		break;
	case t_uint:
	    lkind = lu64;		break;
	case t_exact:
	    lkind = lint;		break;
	case t_float32:
	    lkind = lf32;		break;
	case t_float:
	    lkind = lf64;		break;
	case t_inexact:
	    lkind = lrel;		break;
	case t_dynamic:
	    lkind = lint|lrel;		break;
	default:
	    lkind = 0;			break;
    }
    if ((same = (ast2 == null ||
		 (ast0 && east_node(ast0)->code == east_node(ast2)->code &&
		  east_node(ast0)->csymbol.symbol ==
		  east_node(ast2)->csymbol.symbol)))) {
	rkind = lkind >> 8;	rtype = ltype;		rsoff = lsoff;
	rcode = lcode;		rtoff = ltoff;		rvoff = lvoff;
	rcdyn = lcdyn;
    }
    else {
	rkind = ast2->itype;
	rtype = east_node(ast2)->csymbol.symbol->type;
	rsoff = east_node(ast2)->csymbol.symbol->offset;
	switch (rcode = east_node(ast2)->code) {
	    case eop_ld:	case eop_ldt:
		rtoff = -4;	rvoff = 0;
		break;
	    case eop_lb:	case eop_lbt:
		rtoff = rsoff * sizeof(evalue_t) + offsetof(evalue_t, t);
		rvoff = rsoff * sizeof(evalue_t) + offsetof(evalue_t, v.o);
		break;
	    case eop_lc:
		rtoff = -4;	rvoff = rsoff;
		rcdyn = rtype == t_void || rtype > elast_basic_type;
		break;
	    default:
		abort();
	}
	switch (rkind) {
	    case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	    case t_int32:
		rkind = ri32;		break;
	    case t_uint32:	case t_int:
		rkind = ri64;		break;
	    case t_uint:
		rkind = ru64;		break;
	    case t_exact:
		rkind = rint;		break;
	    case t_float32:
		rkind = rf32;		break;
	    case t_float:
		rkind = rf64;		break;
	    case t_inexact:
		rkind = rrel;		break;
	    case t_dynamic:
		rkind = rint|rrel;	break;
	    default:
		rkind = 0;		break;
	}
    }
#  if __WORDSIZE == 32
    switch (lkind|rkind) {
	case lf32|ri64:		case lf32|ru64:		case lf32|rint:
	case lf64|ri64:		case lf64|ru64:		case lf64|rint:
	case lrel|ri64:		case lrel|ru64:		case lrel|rint:
	case li64|rf32:		case li64|rf64:		case li64|rrel:
	case lu64|rf32:		case lu64|rf64:		case lu64|rrel:
	case lint|rf32:		case lint|rf64:		case lint|rrel:
	    lkind = rkind = 0;
	    if (lcode == eop_noop)
		emit_sync();
	    break;
	case lint|lrel|rf32:	case lint|lrel|rf64:	case lint|lrel|rrel:
	    lkind &= ~lint;
	    break;
	case lf32|rint|rrel:	case lf64|rint|rrel:	case lrel|rint|rrel:
	    rkind &= ~rint;
	    break;
	default:
	    break;
    }
#  endif
    if (lkind & (li32|li64|lu64|lint)) {
	if (rkind & (ri32|ri64|ru64|rint))
	    doint = true;
	else if (
#  if __WORDSIZE == 32
		 lkind == li32 &&
#  endif
		 (rkind & (rf32|rf64|rrel)))
	    doint = true;
    }
    if (lkind & (lf32|lf64|lrel)) {
	if (rkind & (rf32|rf64|rrel))
	    doflt = true;
	else if (
#  if __WORDSIZE == 32
		 rkind == ri32
#  else
		 rkind & (ri32|ri64|ru64|rint)
#  endif
		 )
	    doflt = true;
    }
    if (doint || doflt) {
	switch (lcode) {
	    case eop_noop:
		lbase = JIT_V0;
		break;
	    case eop_ld:		case eop_ldt:
		lbase = JIT_R1;
		jit_ldi(lbase, (jit_word_t)
			((eint8_t *)eds + lsoff * sizeof(eobject_t)));
		break;
	    case eop_lb:	case eop_lbt:
		lbase = JIT_R1;
		jit_ldxi(lbase, JIT_V0, offsetof(ethread_t, ebp));
		break;
	    case eop_lc:
		lbase = JIT_R1;
		jit_ldxi(lbase, JIT_V0, offsetof(ethread_t, ebp));
		switch (rcode) {
		    case eop_noop:	case eop_ld:	case eop_ldt:
		    case eop_lc:
			jit_ldxi(lbase, lbase,
				 -2 * sizeof(evalue_t) +
				 offsetof(evalue_t, v.o));
			break;
		    case eop_lb:	case eop_lbt:
			/* cannot be same */
			rbase = JIT_R1;	lbase = JIT_R2;
			jit_ldxi(lbase, rbase,
				 -2 * sizeof(evalue_t) +
				 offsetof(evalue_t, v.o));
			break;
		    default:
			abort();
		}
		break;
	    default:
		abort();
	}
	if (same) {
	    rbase = lbase;
	    if (lcdyn) {
		jit_ldxi(lbase, lbase, lvoff);
		lvoff = rvoff = 0;
	    }
	}
	else {
	    switch (rcode) {
		case eop_ld:	case eop_ldt:
		    rbase = JIT_R2;
		    jit_ldi(rbase, (jit_word_t)
			    ((eint8_t *)eds + rsoff * sizeof(eobject_t)));
		    break;
		case eop_lb:	case eop_lbt:
		    switch (lcode) {
			case eop_noop:
			    rbase = JIT_R1;
			    jit_ldxi(rbase, JIT_V0, offsetof(ethread_t, ebp));
			    break;
			case eop_ld:	case eop_ldt:
			    rbase = JIT_R2;
			    jit_ldxi(rbase, JIT_V0, offsetof(ethread_t, ebp));
			    break;
			case eop_lb:	case eop_lbt:
			    rbase = lbase;
			    break;
			case eop_lc:
			    /* rbase already set */
			    break;
			default:
			    abort();
		    }
		    break;
		case eop_lc:
		    switch (lcode) {
			case eop_noop:
			    rbase = JIT_R1;
			    goto load_class_second;
			case eop_ld:	case eop_ldt:
			    rbase = JIT_R2;
			load_class_second:
			    jit_ldxi(rbase, JIT_V0, offsetof(ethread_t, ebp));
			    jit_ldxi(rbase, rbase,
				     -2 * sizeof(evalue_t) +
				     offsetof(evalue_t, v.o));
			    break;
			case eop_lb:	case eop_lbt:
			    rbase = JIT_R2;
			    jit_ldxi(rbase, lbase,
				     -2 * sizeof(evalue_t) +
				     offsetof(evalue_t, v.o));
			    break;
			case eop_lc:
			    rbase = lbase;
			    break;
			default:
			    abort();
		    }
		    break;
		default:
		    abort();
	    }
	    if (rcdyn) {
		jit_ldxi(JIT_R2, rbase, rvoff);
		rbase = JIT_R2;
		rvoff = 0;
	    }
	    if (lcdyn) {
		jit_ldxi(lbase, lbase, lvoff);
		lvoff = 0;
	    }
	}
    }
    switch (lkind|rkind) {
	case li32|ri32:
	    switch (lcode) {
		case eop_noop:
		    maybe_reload_ireg32_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, t_int32);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, ltype);
		    break;
		default:
		    abort();
	    }
	    if (same)
		jit_movr(JIT_R0, JIT_V1);
	    else {
		switch (rcode) {
		    case eop_ld:	case eop_lb:
			load_ireg_reg_type(rbase, rvoff,
					   JIT_R0, JIT_R2, t_int32);
			break;
		    case eop_ldt:	case eop_lbt:	case eop_lc:
			load_ireg_reg_type(rbase, rvoff, JIT_R0, JIT_R2, rtype);
			break;
		    default:
			abort();
		}
	    }
	    switch (east_node(ast3)->code) {
		case eop_lt:	jit_ltr(JIT_V1, JIT_V1, JIT_R0);	break;
		case eop_le:	jit_ler(JIT_V1, JIT_V1, JIT_R0);	break;
		case eop_eq:	jit_eqr(JIT_V1, JIT_V1, JIT_R0);	break;
		case eop_ge:	jit_ger(JIT_V1, JIT_V1, JIT_R0);	break;
		case eop_gt:	jit_gtr(JIT_V1, JIT_V1, JIT_R0);	break;
		default:	jit_ner(JIT_V1, JIT_V1, JIT_R0);	break;
	    }
	    ejit_sync = ejit_sync_register;
	    break;
				case li32|ri64:		case li32|ru64:
	case li64|ri32:		case li64|ri64:		case li64|ru64:
	case lu64|ri32:		case lu64|ri64:		case lu64|ru64:
	    if ((lkind & lu64) || (rkind & ru64))
		done = jit_forward();
	    switch (lcode) {
		case eop_noop:
		    if (!(ejit_sync & ejit_sync_register)) {
			assert(ejit_sync & ejit_sync_implicit);
			load_ireg_implicit();
		    }
		    else {
			if (!(ejit_sync & ejit_sync_int_ext))
			    zero_sign_extend(ltype);
			if (!(ejit_sync & ejit_sync_implicit))
			    store_ireg_implicit(true);
		    }
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, t_int);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, ltype);
		    zero_sign_extend_reg(ltype, JIT_V1, JIT_V2);
		    break;
		default:
		    abort();
	    }
	    if (lkind & lu64) {
#  if __WORDSIZE == 32
		lnext = jit_blti(JIT_V2, 0);
#  else
		lnext = jit_blti(JIT_V1, 0);
#  endif
	    }
	    if (same) {
		jit_movr(JIT_R0, JIT_V1);
#  if __WORDSIZE == 32
		jit_movr(JIT_R2, JIT_V2);
#  endif
	    }
	    else {
		switch (rcode) {
		    case eop_ld:	case eop_lb:
			load_ireg_reg_type(rbase, rvoff, JIT_R0, JIT_R2, t_int);
			break;
		    case eop_ldt:	case eop_lbt:	case eop_lc:
			load_ireg_reg_type(rbase, rvoff, JIT_R0, JIT_R2, rtype);
			zero_sign_extend_reg(rtype, JIT_R0, JIT_R2);
			break;
		    default:
			abort();
		}
		if (rkind & ru64) {
#  if __WORDSIZE == 32
		    rnext = jit_blti(JIT_R2, 0);
#  else
		    rnext = jit_blti(JIT_R0, 0);
#  endif
		}
	    }
#  if __WORDSIZE == 32
	    switch (east_node(ast3)->code) {
		case eop_lt:
		    jump = jit_bner(JIT_V2, JIT_R2);
		    jit_ltr_u(JIT_V1, JIT_V1, JIT_R0);
		    temp = jit_jmpi();
		    jit_patch(jump);
		    jit_ltr(JIT_V1, JIT_V2, JIT_R2);
		    jit_patch(temp);
		    break;
		case eop_le:
		    jump = jit_bner(JIT_V2, JIT_R2);
		    jit_ler_u(JIT_V1, JIT_V1, JIT_R0);
		    temp = jit_jmpi();
		    jit_patch(jump);
		    jit_ltr(JIT_V1, JIT_V2, JIT_R2);
		    jit_patch(temp);
		    break;
		case eop_eq:
		    jit_eqr(JIT_V1, JIT_V1, JIT_R0);
		    jit_eqr(JIT_V2, JIT_V2, JIT_R2);
		    jit_andr(JIT_V1, JIT_V1, JIT_V2);
		    break;
		case eop_ge:
		    jump = jit_bner(JIT_V2, JIT_R2);
		    jit_ger_u(JIT_V1, JIT_V1, JIT_R0);
		    temp = jit_jmpi();
		    jit_patch(jump);
		    jit_gtr(JIT_V1, JIT_V2, JIT_R2);
		    jit_patch(temp);
		    break;
		case eop_gt:
		    jump = jit_bner(JIT_V2, JIT_R2);
		    jit_gtr_u(JIT_V1, JIT_V1, JIT_R0);
		    temp = jit_jmpi();
		    jit_patch(jump);
		    jit_gtr(JIT_V1, JIT_V2, JIT_R2);
		    jit_patch(temp);
		    break;
		default:
		    jit_ner(JIT_V1, JIT_V1, JIT_R0);
		    jit_ner(JIT_V2, JIT_V2, JIT_R2);
		    jit_orr(JIT_V1, JIT_V1, JIT_V2);
		    break;
	    }
	    if ((lkind & lu64) || (rkind & ru64))
		jit_movi(JIT_V2, 0);
#  else
	    switch (east_node(ast3)->code) {
		case eop_lt:	jit_ltr(JIT_V1, JIT_V1, JIT_R0);	break;
		case eop_le:	jit_ler(JIT_V1, JIT_V1, JIT_R0);	break;
		case eop_eq:	jit_eqr(JIT_V1, JIT_V1, JIT_R0);	break;
		case eop_ge:	jit_ger(JIT_V1, JIT_V1, JIT_R0);	break;
		case eop_gt:	jit_gtr(JIT_V1, JIT_V1, JIT_R0);	break;
		default:	jit_ner(JIT_V1, JIT_V1, JIT_R0);	break;
	    }
#  endif
	    if ((lkind & lu64) || (rkind & ru64)) {
		store_ireg_implicit(lcode != eop_noop);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
		goto fallback;
	    }
	    ejit_sync = ejit_sync_register;
	    break;
	case li32|rf32:		case li32|rf64:
#  if __WORDSIZE == 64
	case li64|rf32:		case li64|rf64:
	case lu64|rf32:		case lu64|rf64:
#  endif
	    switch (lcode) {
		case eop_noop:
		    if (lkind & lu64) {
			if (!(ejit_sync & ejit_sync_register))
			    load_ireg_implicit();
			else
			    store_ireg_implicit(true);
		    }
		    else
			maybe_reload_ireg_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, t_int);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, ltype);
		    break;
		default:
		    abort();
	    }
	    if (lkind & lu64)
		lnext = jit_blti(JIT_V1, 0);
	    jit_extr_d(JIT_F0, JIT_V1);
	    switch (rcode) {
		case eop_ld:	case eop_lb:
		    load_freg_reg_type(rbase, rvoff, JIT_F1, JIT_F1, t_float);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_freg_reg_type(rbase, rvoff, JIT_F1, JIT_F1, rtype);
		    if (rkind & rf32)
			jit_extr_f_d(JIT_F1, JIT_F1);
		    break;
		default:
		    abort();
	    }
	    goto float_cmp;
	case lf32|ri32:		case lf64|ri32:
#  if __WORDSIZE == 64
	case lf32|ri64:		case lf32|ru64:
	case lf64|ri64:		case lf64|ru64:
#  endif
	    switch (lcode) {
		case eop_noop:
		    if (!(ejit_sync & ejit_sync_register)) {
			assert(ejit_sync & ejit_sync_implicit);
			load_freg_implicit();
		    }
		    else {
			if ((lkind & lf32) &&
			    !(ejit_sync & ejit_sync_float_ext))
			    jit_extr_f_d(JIT_F0, JIT_F1);
			if (rkind & ru64)
			    store_freg_implicit(true);
		    }
		    break;
		case eop_ld:	case eop_lb:
		    load_freg_reg_type(lbase, lvoff, JIT_F0, JIT_F0, t_float);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_freg_reg_type(lbase, lvoff, JIT_F0, JIT_F0, ltype);
		    if (lkind & lf32)
			jit_extr_f_d(JIT_F0, JIT_F0);
		    break;
		default:
		    abort();
	    }
	    switch (rcode) {
		case eop_ld:	case eop_lb:
		    load_ireg_reg_type(rbase, rvoff, JIT_R0, JIT_R2, t_int);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_reg_type(rbase, rvoff, JIT_R0, JIT_R2, rtype);
		    break;
		default:
		    abort();
	    }
	    if (rkind & ru64)
		rnext = jit_blti(JIT_R0, 0);
	    jit_extr_d(JIT_F1, JIT_R0);
	    goto float_cmp;
	case lf32|rf32:		case lf32|rf64:
	case lf64|rf32:		case lf64|rf64:
	    switch (lcode) {
		case eop_noop:
		    if (lkind & lf32) {
			if (!(ejit_sync & ejit_sync_register)) {
			    assert(ejit_sync & ejit_sync_implicit);
			    load_freg_implicit();
			}
			else if (!(ejit_sync & ejit_sync_float_ext))
			    jit_extr_f_d(JIT_F0, JIT_F1);
		    }
		    else
			maybe_reload_freg_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_freg_reg_type(lbase, lvoff, JIT_F0, JIT_F0, t_float);
		    load_freg(lbase, lvoff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_freg_reg_type(lbase, lvoff, JIT_F0, JIT_F0, ltype);
		    if (lkind & lf32)
			jit_extr_f_d(JIT_F0, JIT_F0);
		    break;
		default:
		    abort();
	    }
	    if (same)
		jit_movr_d(JIT_F1, JIT_F0);
	    else {
		switch (rcode) {
		    case eop_ld:	case eop_lb:
			load_freg_reg_type(rbase, rvoff,
					   JIT_F1, JIT_F1, t_float);
			break;
		    case eop_ldt:	case eop_lbt:	case eop_lc:
			load_freg_reg_type(rbase, rvoff, JIT_F1, JIT_F1, rtype);
			if (rkind & rf32)
			    jit_extr_f_d(JIT_F1, JIT_F1);
			break;
		    default:
			abort();
		}
	    }
	float_cmp:
	    switch (east_node(ast3)->code) {
		case eop_ne:	jit_ner_d(JIT_V1, JIT_F0, JIT_F1);	break;
		case eop_lt:	jit_ltr_d(JIT_V1, JIT_F0, JIT_F1);	break;
		case eop_le:	jit_ler_d(JIT_V1, JIT_F0, JIT_F1);	break;
		case eop_eq:	jit_eqr_d(JIT_V1, JIT_F0, JIT_F1);	break;
		case eop_ge:	jit_ger_d(JIT_V1, JIT_F0, JIT_F1);	break;
		default:	jit_gtr_d(JIT_V1, JIT_F0, JIT_F1);	break;
	    }
	    if (lnext || rnext) {
		assert(done == null);
		done = jit_forward();
#  if __WORDSIZE == 32
		jit_movi(JIT_V2, 0);
#  endif
		store_ireg_implicit(true);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
		goto fallback;
	    }
	    ejit_sync = ejit_sync_register;
	    break;
	default:
	    if (doint || doflt) {
		done = jit_forward();
		fail = jit_forward();
		jump = null;
		switch (lcode) {
		    case eop_noop:
			emit_sync();
			break;
		    case eop_ld:
			jump = jit_beqi(lbase, 0);
			break;
		    case eop_lc:
			if (lcdyn) {
			    assert(!(lkind & ~(lint|lrel)));
			    jump = jit_beqi(lbase, 0);
			}
			break;
		    default:
			break;
		}
		if (jump)
		    jit_patch_at(jump, fail);
		if (!same) {
		    jump = null;
		    switch (rcode) {
			case eop_ld:
			    jump = jit_beqi(rbase, 0);
			    break;
			case eop_lc:
			    if (rcdyn) {
				assert(!(rkind & ~(rint|rrel)));
				jump = jit_beqi(rbase, 0);
			    }
			    break;
			default:
			    break;
		    }
		    if (jump)
			jit_patch_at(jump, fail);
		}
	    }
	    if (doint) {
		if (lkind & lint) {
		    switch (lcode) {
			case eop_noop:	case eop_ld:	case eop_lb:
			case eop_lc:
			    jit_ldxi_i(JIT_R0, lbase, ltoff);
			    break;
			default:
			    abort();
		    }
		    lnext = jit_bnei(JIT_R0, t_int);
		}
		switch (lcode) {
		    case eop_noop:
			maybe_reload_ireg_implicit();
			break;
		    case eop_ld:	case eop_lb:
		    left_int_dynamic:
			load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, t_int);
			break;
		    case eop_ldt:	case eop_lbt:
		    left_int_static:
			load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, ltype);
			zero_sign_extend_reg(ltype, JIT_V1, JIT_V2);
			break;
		    case eop_lc:
			if (lcdyn)	goto left_int_dynamic;
			goto left_int_static;
		    default:
			abort();
		}
		if (lkind & lu64) {
#  if __WORDSIZE == 32
		    jump = jit_blti(JIT_V2, 0);
#  else
		    jump = jit_blti(JIT_V1, 0);
#  endif
		    jit_patch_at(jump, fail);
		}
		if (same) {
		    jit_movr(JIT_R0, JIT_V1);
#  if __WORDSIZE == 32
		    jit_movr(JIT_R2, JIT_V2);
#  endif
		}
		else {
		    jext = null;
		    if (rkind & (rint|rrel)) {
			switch (rcode) {
			    case eop_noop:	case eop_ld:	case eop_lb:
			    case eop_lc:
				jit_ldxi_i(JIT_R0, rbase, rtoff);
				break;
			    default:
				abort();
			}
			if (
#  if __WORDSIZE == 32
			    (lkind == li32) &&
#  endif
			    (rkind & rrel)) {
			    jext = jit_beqi(JIT_R0, t_int);
			    jump = jit_bnei(JIT_R0, t_float);
			    jit_patch_at(jump, fail);
			}
			else
			    rnext = jit_bnei(JIT_R0, t_int);
		    }
		    if (
#  if __WORDSIZE == 32
			(lkind == li32) &&
#  endif
			(rkind & (rf32|rf64|rrel))) {
			switch (rcode) {
			    case eop_ld:	case eop_lb:
			    right_float_ext_dynamic:
				load_freg_reg_type(rbase, rvoff,
						   JIT_F1, JIT_F1, t_float);
				break;
			    case eop_ldt:	case eop_lbt:
			    right_float_ext_static:
				load_freg_reg_type(rbase, rvoff,
						   JIT_F1, JIT_F1, rtype);
				if (rkind & rf32)
				    jit_extr_f_d(JIT_F1, JIT_F1);
				break;
			    case eop_lc:
				if (rcdyn)	goto right_float_ext_dynamic;
				goto right_float_ext_static;
			    default:
				abort();
			}
			jit_extr_d(JIT_F0, JIT_V1);
			switch (east_node(ast3)->code) {
			    case eop_ne:
				jit_ner_d(JIT_V1, JIT_F0, JIT_F1);	break;
			    case eop_lt:
				jit_ltr_d(JIT_V1, JIT_F0, JIT_F1);	break;
			    case eop_le:
				jit_ler_d(JIT_V1, JIT_F0, JIT_F1);	break;
			    case eop_eq:
				jit_eqr_d(JIT_V1, JIT_F0, JIT_F1);	break;
			    case eop_ge:
				jit_ger_d(JIT_V1, JIT_F0, JIT_F1);	break;
			    default:
				jit_gtr_d(JIT_V1, JIT_F0, JIT_F1);	break;
			}
#  if __WORDSIZE == 32
			jit_movi(JIT_V2, 0);
#  endif
			store_ireg_implicit(true);
			jump = jit_jmpi();
			jit_patch_at(jump, done);
		    }
		    if (jext)
			jit_patch(jext);
		    switch (rcode) {
			case eop_ld:	case eop_lb:
			right_int_dynamic:
			    load_ireg_reg_type(rbase, rvoff,
					       JIT_R0, JIT_R2, t_int);
			    break;
			case eop_ldt:	case eop_lbt:
			right_int_static:
			    load_ireg_reg_type(rbase, rvoff,
					       JIT_R0, JIT_R2, rtype);
			    zero_sign_extend_reg(rtype, JIT_R0, JIT_R2);
			    break;
			case eop_lc:
			    if (rcdyn)	goto right_int_dynamic;
			    goto right_int_static;
			default:
			    abort();
		    }
		    if (rkind & ru64) {
#  if __WORDSIZE == 32
			jump = jit_blti(JIT_R2, 0);
#  else
			jump = jit_blti(JIT_R0, 0);
#  endif
			jit_patch_at(jump, fail);
		    }
		}
#  if __WORDSIZE == 32
		switch (east_node(ast3)->code) {
		    case eop_lt:
			jump = jit_bner(JIT_V2, JIT_R2);
			jit_ltr_u(JIT_V1, JIT_V1, JIT_R0);
			temp = jit_jmpi();
			jit_patch(jump);
			jit_ltr(JIT_V1, JIT_V2, JIT_R2);
			jit_patch(temp);
			break;
		    case eop_le:
			jump = jit_bner(JIT_V2, JIT_R2);
			jit_ler_u(JIT_V1, JIT_V1, JIT_R0);
			temp = jit_jmpi();
			jit_patch(jump);
			jit_ltr(JIT_V1, JIT_V2, JIT_R2);
			jit_patch(temp);
			break;
		    case eop_eq:
			jit_eqr(JIT_V1, JIT_V1, JIT_R0);
			jit_eqr(JIT_V2, JIT_V2, JIT_R2);
			jit_andr(JIT_V1, JIT_V1, JIT_V2);
			break;
		    case eop_ge:
			jump = jit_bner(JIT_V2, JIT_R2);
			jit_ger_u(JIT_V1, JIT_V1, JIT_R0);
			temp = jit_jmpi();
			jit_patch(jump);
			jit_gtr(JIT_V1, JIT_V2, JIT_R2);
			jit_patch(temp);
			break;
		    case eop_gt:
			jump = jit_bner(JIT_V2, JIT_R2);
			jit_gtr_u(JIT_V1, JIT_V1, JIT_R0);
			temp = jit_jmpi();
			jit_patch(jump);
			jit_gtr(JIT_V1, JIT_V2, JIT_R2);
			jit_patch(temp);
			break;
		    default:
			jit_ner(JIT_V1, JIT_V1, JIT_R0);
			jit_ner(JIT_V2, JIT_V2, JIT_R2);
			jit_orr(JIT_V1, JIT_V1, JIT_V2);
			break;
		}
		jit_movi(JIT_V2, 0);
#  else
		switch (east_node(ast3)->code) {
		    case eop_ne:jit_ner(JIT_V1, JIT_V1, JIT_R0);	break;
		    case eop_lt:jit_ltr(JIT_V1, JIT_V1, JIT_R0);	break;
		    case eop_le:jit_ler(JIT_V1, JIT_V1, JIT_R0);	break;
		    case eop_eq:jit_eqr(JIT_V1, JIT_V1, JIT_R0);	break;
		    case eop_ge:jit_ger(JIT_V1, JIT_V1, JIT_R0);	break;
		    default:	jit_gtr(JIT_V1, JIT_V1, JIT_R0);	break;
		}
#  endif
		store_ireg_implicit(lcode != eop_noop ||
				    !(ejit_sync & ejit_sync_implicit));
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (doflt) {
		if (lnext) {
		    jit_patch(lnext);
		    lnext = null;
		}
		if (rnext) {
		    jit_patch(rnext);
		    rnext = null;
		}
		if (lkind & lrel) {
		    if (lnext == null || rnext != null) {
			switch (lcode) {
			    case eop_noop:	case eop_ld:	case eop_lb:
			    case eop_lc:
				jit_ldxi_i(JIT_R0, lbase, ltoff);
				break;
			    default:
				abort();
			}
		    }
		    lnext = jit_bnei(JIT_R0, t_float);
		}
		switch (lcode) {
		    case eop_noop:
			maybe_reload_freg_implicit();
			break;
		    case eop_ld:	case eop_lb:
		    left_float_dynamic:
			load_freg_reg_type(lbase, lvoff,
					   JIT_F0, JIT_F0, t_float);
			break;
		    case eop_ldt:	case eop_lbt:
		    left_float_static:
			load_freg_reg_type(lbase, lvoff,
					   JIT_F0, JIT_F0, ltype);
			if (lkind & lf32)
			    jit_extr_f_d(JIT_F0, JIT_F0);
			break;
		    case eop_lc:
			if (lcdyn)	goto left_float_dynamic;
			goto left_float_static;
		    default:
			abort();
		}
		/* set if generating code to convert int to float */
		jcvt = null;
		if (same)
		    jit_movr_d(JIT_F1, JIT_F0);
		else {
		    jext = null;
		    if (rkind & (rint|rrel)) {
			switch (rcode) {
			    case eop_noop:	case eop_ld:	case eop_lb:
			    case eop_lc:
				jit_ldxi_i(JIT_R0, rbase, rtoff);
				break;
			    default:
				abort();
			}
#  if __WORDSIZE == 64
			if (rkind & rint) {
			    jext = jit_beqi(JIT_R0, t_float);
			    jump = jit_bnei(JIT_R0, t_int);
			    jit_patch_at(jump, fail);
			}
			else
#  endif
			    rnext = jit_bnei(JIT_R0, t_float);
		    }
		    if (
#  if __WORDSIZE == 32
			(rkind == ri32)
#  else
			(rkind & (ri32|ri64|ru64|rint))
#  endif
			) {
			switch (rcode) {
			    case eop_ld:	case eop_lb:
			    right_int_ext_dynamic:
				load_ireg_reg_type(rbase, rvoff,
						   JIT_R0, JIT_R2, t_int);
				break;
			    case eop_ldt:	case eop_lbt:
			    right_int_ext_static:
				load_ireg_reg_type(rbase, rvoff,
						   JIT_R0, JIT_R2, rtype);
				zero_sign_extend_reg(rtype, JIT_R0, JIT_R2);
				break;
			    case eop_lc:
				if (rcdyn)	goto right_int_ext_dynamic;
				goto right_int_ext_static;
			    default:
				abort();
			}
#  if __WORDSIZE == 64
			if (rkind & ru64) {
			    jump = jit_blti(JIT_R0, 0);
			    jit_patch_at(jump, fail);
			}
#  endif
			jit_extr_d(JIT_F1, JIT_R0);
			jcvt = jit_jmpi();
		    }
		    if (jext)
			jit_patch(jext);
		    switch (rcode) {
			case eop_ld:	case eop_lb:
			right_float_dynamic:
			    load_freg_reg_type(rbase, rvoff,
					       JIT_F1, JIT_F1, t_float);
			    break;
			case eop_ldt:	case eop_lbt:
			right_float_static:
			    load_freg_reg_type(rbase, rvoff,
					       JIT_F1, JIT_F1, rtype);
			    if (rkind & rf32)
				jit_extr_f_d(JIT_F1, JIT_F1);
			    break;
			case eop_lc:
			    if (rcdyn)	goto right_float_dynamic;
			    goto right_float_static;
			default:
			    abort();
		    }
		}
		/* if did convert int to float */
		if (jcvt)
		    jit_patch(jcvt);
		switch (east_node(ast3)->code) {
		    case eop_ne:jit_ner_d(JIT_V1, JIT_F0, JIT_F1);	break;
		    case eop_lt:jit_ltr_d(JIT_V1, JIT_F0, JIT_F1);	break;
		    case eop_le:jit_ler_d(JIT_V1, JIT_F0, JIT_F1);	break;
		    case eop_eq:jit_eqr_d(JIT_V1, JIT_F0, JIT_F1);	break;
		    case eop_ge:jit_ger_d(JIT_V1, JIT_F0, JIT_F1);	break;
		    default:	jit_gtr_d(JIT_V1, JIT_F0, JIT_F1);	break;
		}
#  if __WORDSIZE == 32
		jit_movi(JIT_V2, 0);
#  endif
		store_ireg_implicit(true);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	fallback:
	    if (fail)
		jit_link(fail);
	    if (lnext)
		jit_patch(lnext);
	    if (rnext)
		jit_patch(rnext);
	    switch (lcode) {
		case eop_noop:						break;
		case eop_ld:	call_vi(evm_ld, lsoff);			break;
		case eop_ldt:	call_vii(evm_ldt, lsoff, ltype);	break;
		case eop_lb:	call_vi(evm_lb, lsoff);			break;
		case eop_lbt:	call_vii(evm_lbt, lsoff, ltype);	break;
		case eop_lc:	call_vii(evm_lc, lsoff, ltype);		break;
		default:	abort();
	    }
	    jit_calli(evm_push);
	    if (!same) {
		switch (rcode) {
		    case eop_noop:					break;
		    case eop_ld:	call_vi(evm_ld, rsoff);		break;
		    case eop_ldt:	call_vii(evm_ldt, rsoff, rtype);break;
		    case eop_lb:	call_vi(evm_lb, rsoff);		break;
		    case eop_lbt:	call_vii(evm_lbt, rsoff, rtype);break;
		    case eop_lc:	call_vii(evm_lc, rsoff, rtype);	break;
		    default:		abort();
		}
	    }
	    switch (east_node(ast3)->code) {
		case eop_ne:		jit_calli(evm_ne);		break;
		case eop_lt:		jit_calli(evm_lt);		break;
		case eop_le:		jit_calli(evm_le);		break;
		case eop_eq:		jit_calli(evm_eq);		break;
		case eop_ge:		jit_calli(evm_ge);		break;
		default:		jit_calli(evm_gt);		break;
	    }
	    load_ireg32_implicit();
#  if __WORDSIZE == 32
	    jit_movi(JIT_V2, 0);
#  endif
	    if (done)
		jit_link(done);
	    ejit_sync = ejit_sync_register|ejit_sync_implicit|ejit_sync_int_ext;
	    break;
    }
    ejit_type = ast3->itype;
}

static void
emit_load_push_load_cmp_jmp(east_list_t *ast0, east_list_t *ast1,
			    east_list_t *ast2, east_list_t *ast3,
			    east_list_t *ast4)
{
    ebool_t		 same;
    ecode_t		 code;
#  if __WORDSIZE == 32
    jit_node_t		*temp;
#  endif
    eword_t		 index;
    elabel_t		*label;
    jit_node_t		*done;
    jit_node_t		*fail,  *jcvt;
    jit_node_t		*jext,  *jump;
    jit_node_t		*lnext, *rnext;
    ecode_t		 lcode,  rcode;
    etype_t		 ltype,  rtype;
    eint32_t		 lsoff,  rsoff;
    eint32_t		 ltoff,  rtoff;
    eint32_t		 lvoff,  rvoff;
    eint32_t		 lcdyn,  rcdyn;
    jit_int32_t		 lbase,  rbase;
    ebool_t		 doint,  doflt;
    eint32_t		 lkind,  rkind;

    if (east_node(ast4)->code == eop_jt)
	code = east_node(ast3)->code;
    else {
	switch (east_node(ast3)->code) {
	    case eop_lt:	code = eop_ge;		break;
	    case eop_le:	code = eop_gt;		break;
	    case eop_eq:	code = eop_ne;		break;
	    case eop_ge:	code = eop_lt;		break;
	    case eop_gt:	code = eop_le;		break;
	    default:		code = eop_eq;		break;
	}
    }
    label = east_node(ast4)->clabel.label;
    if (label->value == null)
	allocate_forward_label(label);
    index = eget_fixnum(label->value);
    lbase = rbase = JIT_R1;
    done = fail = lnext = rnext = null;
    doint = doflt = lcdyn = rcdyn = false;
    if (ast0) {
	lkind = ast0->itype;
	ltype = east_node(ast0)->csymbol.symbol->type;
	lsoff = east_node(ast0)->csymbol.symbol->offset;
	switch (lcode = east_node(ast0)->code) {
	    case eop_ld:	case eop_ldt:
		ltoff = -4;	lvoff = 0;
		break;
	    case eop_lb:	case eop_lbt:
		ltoff = lsoff * sizeof(evalue_t) + offsetof(evalue_t, t);
		lvoff = lsoff * sizeof(evalue_t) + offsetof(evalue_t, v.o);
		break;
	    case eop_lc:
		ltoff = -4;	lvoff = lsoff;
		lcdyn = ltype == t_void || ltype > elast_basic_type;
		break;
	    default:
		abort();
	}
    }
    else {
	lkind = ltype = ast1->rtype;
	lsoff = 0;
	lcode = eop_noop;
	ltoff = offsetof(ethread_t, r0) + offsetof(evalue_t, t);
	lvoff = offsetof(ethread_t, r0) + offsetof(evalue_t, v.o);
    }
    switch (lkind) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    lkind = li32;		break;
	case t_uint32:	case t_int:
	    lkind = li64;		break;
	case t_uint:
	    lkind = lu64;		break;
	case t_exact:
	    lkind = lint;		break;
	case t_float32:
	    lkind = lf32;		break;
	case t_float:
	    lkind = lf64;		break;
	case t_inexact:
	    lkind = lrel;		break;
	case t_dynamic:
	    lkind = lint|lrel;		break;
	default:
	    lkind = 0;			break;
    }
    if ((same = (ast2 == null ||
		 (ast0 && east_node(ast0)->code == east_node(ast2)->code &&
		  east_node(ast0)->csymbol.symbol ==
		  east_node(ast2)->csymbol.symbol)))) {
	rkind = lkind >> 8;	rtype = ltype;		rsoff = lsoff;
	rcode = lcode;		rtoff = ltoff;		rvoff = lvoff;
	rcdyn = lcdyn;
    }
    else {
	rkind = ast2->itype;
	rtype = east_node(ast2)->csymbol.symbol->type;
	rsoff = east_node(ast2)->csymbol.symbol->offset;
	switch (rcode = east_node(ast2)->code) {
	    case eop_ld:	case eop_ldt:
		rtoff = -4;	rvoff = 0;
		break;
	    case eop_lb:	case eop_lbt:
		rtoff = rsoff * sizeof(evalue_t) + offsetof(evalue_t, t);
		rvoff = rsoff * sizeof(evalue_t) + offsetof(evalue_t, v.o);
		break;
	    case eop_lc:
		rtoff = -4;	rvoff = rsoff;
		rcdyn = rtype == t_void || rtype > elast_basic_type;
		break;
	    default:
		abort();
	}
	switch (rkind) {
	    case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	    case t_int32:
		rkind = ri32;		break;
	    case t_uint32:	case t_int:
		rkind = ri64;		break;
	    case t_uint:
		rkind = ru64;		break;
	    case t_exact:
		rkind = rint;		break;
	    case t_float32:
		rkind = rf32;		break;
	    case t_float:
		rkind = rf64;		break;
	    case t_inexact:
		rkind = rrel;		break;
	    case t_dynamic:
		rkind = rint|rrel;	break;
	    default:
		rkind = 0;		break;
	}
    }
#  if __WORDSIZE == 32
    switch (lkind|rkind) {
	case lf32|ri64:		case lf32|ru64:		case lf32|rint:
	case lf64|ri64:		case lf64|ru64:		case lf64|rint:
	case lrel|ri64:		case lrel|ru64:		case lrel|rint:
	case li64|rf32:		case li64|rf64:		case li64|rrel:
	case lu64|rf32:		case lu64|rf64:		case lu64|rrel:
	case lint|rf32:		case lint|rf64:		case lint|rrel:
	    lkind = rkind = 0;
	    if (lcode == eop_noop)
		emit_sync();
	    break;
	case lint|lrel|rf32:	case lint|lrel|rf64:	case lint|lrel|rrel:
	    lkind &= ~lint;
	    break;
	case lf32|rint|rrel:	case lf64|rint|rrel:	case lrel|rint|rrel:
	    rkind &= ~rint;
	    break;
	default:
	    break;
    }
#  endif
    if (lkind & (li32|li64|lu64|lint)) {
	if (rkind & (ri32|ri64|ru64|rint))
	    doint = true;
	else if (
#  if __WORDSIZE == 32
		 lkind == li32 &&
#  endif
		 (rkind & (rf32|rf64|rrel)))
	    doint = true;
    }
    if (lkind & (lf32|lf64|lrel)) {
	if (rkind & (rf32|rf64|rrel))
	    doflt = true;
	else if (
#  if __WORDSIZE == 32
		 rkind == ri32
#  else
		 rkind & (ri32|ri64|ru64|rint)
#  endif
		 )
	    doflt = true;
    }
    if (doint || doflt) {
	switch (lcode) {
	    case eop_noop:
		lbase = JIT_V0;
		break;
	    case eop_ld:		case eop_ldt:
		lbase = JIT_R1;
		jit_ldi(lbase, (jit_word_t)
			((eint8_t *)eds + lsoff * sizeof(eobject_t)));
		break;
	    case eop_lb:	case eop_lbt:
		lbase = JIT_R1;
		jit_ldxi(lbase, JIT_V0, offsetof(ethread_t, ebp));
		break;
	    case eop_lc:
		lbase = JIT_R1;
		jit_ldxi(lbase, JIT_V0, offsetof(ethread_t, ebp));
		switch (rcode) {
		    case eop_noop:	case eop_ld:	case eop_ldt:
		    case eop_lc:
			jit_ldxi(lbase, lbase,
				 -2 * sizeof(evalue_t) +
				 offsetof(evalue_t, v.o));
			break;
		    case eop_lb:	case eop_lbt:
			/* cannot be same */
			rbase = JIT_R1;	lbase = JIT_R2;
			jit_ldxi(lbase, rbase,
				 -2 * sizeof(evalue_t) +
				 offsetof(evalue_t, v.o));
			break;
		    default:
			abort();
		}
		break;
	    default:
		abort();
	}
	if (same) {
	    rbase = lbase;
	    if (lcdyn) {
		jit_ldxi(lbase, lbase, lvoff);
		lvoff = rvoff = 0;
	    }
	}
	else {
	    switch (rcode) {
		case eop_ld:	case eop_ldt:
		    rbase = JIT_R2;
		    jit_ldi(rbase, (jit_word_t)
			    ((eint8_t *)eds + rsoff * sizeof(eobject_t)));
		    break;
		case eop_lb:	case eop_lbt:
		    switch (lcode) {
			case eop_noop:
			    rbase = JIT_R1;
			    jit_ldxi(rbase, JIT_V0, offsetof(ethread_t, ebp));
			    break;
			case eop_ld:	case eop_ldt:
			    rbase = JIT_R2;
			    jit_ldxi(rbase, JIT_V0, offsetof(ethread_t, ebp));
			    break;
			case eop_lb:	case eop_lbt:
			    rbase = lbase;
			    break;
			case eop_lc:
			    /* rbase already set */
			    break;
			default:
			    abort();
		    }
		    break;
		case eop_lc:
		    switch (lcode) {
			case eop_noop:
			    rbase = JIT_R1;
			    goto load_class_second;
			case eop_ld:	case eop_ldt:
			    rbase = JIT_R2;
			load_class_second:
			    jit_ldxi(rbase, JIT_V0, offsetof(ethread_t, ebp));
			    jit_ldxi(rbase, rbase,
				     -2 * sizeof(evalue_t) +
				     offsetof(evalue_t, v.o));
			    break;
			case eop_lb:	case eop_lbt:
			    rbase = JIT_R2;
			    jit_ldxi(rbase, lbase,
				     -2 * sizeof(evalue_t) +
				     offsetof(evalue_t, v.o));
			    break;
			case eop_lc:
			    rbase = lbase;
			    break;
			default:
			    abort();
		    }
		    break;
		default:
		    abort();
	    }
	    if (rcdyn) {
		jit_ldxi(JIT_R2, rbase, rvoff);
		rbase = JIT_R2;
		rvoff = 0;
	    }
	    if (lcdyn) {
		jit_ldxi(lbase, lbase, lvoff);
		lvoff = 0;
	    }
	}
    }
    switch (lkind|rkind) {
	case ri32|li32:
	    switch (lcode) {
		case eop_noop:
		    maybe_reload_ireg32_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, t_int32);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, ltype);
		    break;
		default:
		    abort();
	    }
	    if (same)
		jit_movr(JIT_R0, JIT_V1);
	    else {
		switch (rcode) {
		    case eop_ld:	case eop_lb:
			load_ireg_reg_type(rbase, rvoff,
					   JIT_R0, JIT_R2, t_int32);
			break;
		    case eop_ldt:	case eop_lbt:	case eop_lc:
			load_ireg_reg_type(rbase, rvoff, JIT_R0, JIT_R2, rtype);
			break;
		    default:
			abort();
		}
	    }
	    switch (code) {
		case eop_lt:	jump = jit_bltr(JIT_V1, JIT_R0);	break;
		case eop_le:	jump = jit_bler(JIT_V1, JIT_R0);	break;
		case eop_eq:	jump = jit_beqr(JIT_V1, JIT_R0);	break;
		case eop_ge:	jump = jit_bger(JIT_V1, JIT_R0);	break;
		case eop_gt:	jump = jit_bgtr(JIT_V1, JIT_R0);	break;
		default:	jump = jit_bner(JIT_V1, JIT_R0);	break;
	    }
	    if (index >= 0)	jit_patch_at(jump, labels[index]);
	    else		record_forward_patch(jump, -index);
	    break;
				case li32|ri64:		case li32|ru64:
	case li64|ri32:		case li64|ri64:		case li64|ru64:
	case lu64|ri32:		case lu64|ri64:		case lu64|ru64:
	    if ((lkind & lu64) || (rkind & ru64))
		done = jit_forward();
	    switch (lcode) {
		case eop_noop:
		    if (!(ejit_sync & ejit_sync_register)) {
			assert(ejit_sync & ejit_sync_implicit);
			load_ireg_implicit();
		    }
		    else {
			if (!(ejit_sync & ejit_sync_int_ext))
			    zero_sign_extend(ltype);
			if (!(ejit_sync & ejit_sync_implicit))
			    store_ireg_implicit(true);
		    }
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, t_int);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, ltype);
		    zero_sign_extend_reg(ltype, JIT_V1, JIT_V2);
		    break;
		default:
		    abort();
	    }
	    if (lkind & lu64) {
#  if __WORDSIZE == 32
		lnext = jit_blti(JIT_V2, 0);
#  else
		lnext = jit_blti(JIT_V1, 0);
#  endif
	    }
	    if (same) {
		jit_movr(JIT_R0, JIT_V1);
#  if __WORDSIZE == 32
		jit_movr(JIT_R2, JIT_V2);
#  endif
	    }
	    else {
		switch (rcode) {
		    case eop_ld:	case eop_lb:
			load_ireg_reg_type(rbase, rvoff, JIT_R0, JIT_R2, t_int);
			break;
		    case eop_ldt:	case eop_lbt:	case eop_lc:
			load_ireg_reg_type(rbase, rvoff, JIT_R0, JIT_R2, rtype);
			zero_sign_extend_reg(rtype, JIT_R0, JIT_R2);
			break;
		    default:
			abort();
		}
		if (rkind & ru64) {
#  if __WORDSIZE == 32
		    rnext = jit_blti(JIT_R2, 0);
#  else
		    rnext = jit_blti(JIT_R0, 0);
#  endif
		}
	    }
#  if __WORDSIZE == 32
	    switch (code) {
		case eop_lt:
		    jump = jit_bltr(JIT_V2, JIT_R2);
		    temp = jit_bgtr(JIT_V2, JIT_R2);
		    if (index >= 0)	jit_patch_at(jump, labels[index]);
		    else		record_forward_patch(jump, -index);
		    jump = jit_bltr_u(JIT_V1, JIT_R0);
		    jit_patch(temp);
		    break;
		case eop_le:
		    jump = jit_bgtr(JIT_R2, JIT_V2);
		    temp = jit_bltr(JIT_R2, JIT_V2);
		    if (index >= 0)	jit_patch_at(jump, labels[index]);
		    else		record_forward_patch(jump, -index);
		    jump = jit_bler_u(JIT_V1, JIT_R0);
		    jit_patch(temp);
		    break;
		case eop_eq:
		    temp = jit_bner(JIT_V1, JIT_R0);
		    jump = jit_beqr(JIT_V2, JIT_R2);
		    jit_patch(temp);
		    break;
		case eop_ge:
		    jump = jit_bltr(JIT_R2, JIT_V2);
		    temp = jit_bgtr(JIT_R2, JIT_V2);
		    if (index >= 0)	jit_patch_at(jump, labels[index]);
		    else		record_forward_patch(jump, -index);
		    jump = jit_bger_u(JIT_V1, JIT_R0);
		    jit_patch(temp);
		    break;
		case eop_gt:
		    jump = jit_bgtr(JIT_V2, JIT_R2);
		    temp = jit_bltr(JIT_V2, JIT_R2);
		    if (index >= 0)	jit_patch_at(jump, labels[index]);
		    else		record_forward_patch(jump, -index);
		    jump = jit_bgtr_u(JIT_V1, JIT_R0);
		    jit_patch(temp);
		    break;
		default:
		    jump = jit_bner(JIT_V1, JIT_R0);
		    if (index >= 0)	jit_patch_at(jump, labels[index]);
		    else		record_forward_patch(jump, -index);
		    jump = jit_bner(JIT_V2, JIT_R2);
		    break;
	    }
#  else
	    switch (code) {
		case eop_lt:	jump = jit_bltr(JIT_V1, JIT_R0);	break;
		case eop_le:	jump = jit_bler(JIT_V1, JIT_R0);	break;
		case eop_eq:	jump = jit_beqr(JIT_V1, JIT_R0);	break;
		case eop_ge:	jump = jit_bger(JIT_V1, JIT_R0);	break;
		case eop_gt:	jump = jit_bgtr(JIT_V1, JIT_R0);	break;
		default:	jump = jit_bner(JIT_V1, JIT_R0);	break;
	    }
#  endif
	    if (index >= 0)	jit_patch_at(jump, labels[index]);
	    else		record_forward_patch(jump, -index);
	    if ((lkind & lu64) || (rkind & ru64)) {
		jump = jit_jmpi();
		jit_patch_at(jump, done);
		goto fallback;
	    }
	    break;
	case li32|rf32:		case li32|rf64:
#  if __WORDSIZE == 64
	case li64|rf32:		case li64|rf64:
	case lu64|rf32:		case lu64|rf64:
#  endif
	    switch (lcode) {
		case eop_noop:
		    if (lkind & lu64) {
			if (!(ejit_sync & ejit_sync_register))
			    load_ireg_implicit();
			else
			    store_ireg_implicit(true);
		    }
		    else
			maybe_reload_ireg_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, t_int);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, ltype);
		    break;
		default:
		    abort();
	    }
	    if (lkind & lu64)
		lnext = jit_blti(JIT_V1, 0);
	    jit_extr_d(JIT_F0, JIT_V1);
	    switch (rcode) {
		case eop_ld:	case eop_lb:
		    load_freg_reg_type(rbase, rvoff, JIT_F1, JIT_F1, t_float);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_freg_reg_type(rbase, rvoff, JIT_F1, JIT_F1, rtype);
		    if (rkind & rf32)
			jit_extr_f_d(JIT_F1, JIT_F1);
		    break;
		default:
		    abort();
	    }
	    goto float_cmp;
	case lf32|ri32:		case lf64|ri32:
#  if __WORDSIZE == 64
	case lf32|ri64:		case lf32|ru64:
	case lf64|ri64:		case lf64|ru64:
#  endif
	    switch (lcode) {
		case eop_noop:
		    maybe_reload_freg_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_freg_reg_type(lbase, lvoff, JIT_F0, JIT_F0, t_float);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_freg_reg_type(lbase, lvoff, JIT_F0, JIT_F0, ltype);
		    if (lkind & lf32)
			jit_extr_f_d(JIT_F0, JIT_F0);
		    break;
		default:
		    abort();
	    }
	    switch (rcode) {
		case eop_ld:	case eop_lb:
		    load_ireg_reg_type(rbase, rvoff, JIT_R0, JIT_R2, t_int);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_reg_type(rbase, rvoff, JIT_R0, JIT_R2, rtype);
		    break;
		default:
		    abort();
	    }
	    if (rkind & ru64)
		rnext = jit_blti(JIT_R0, 0);
	    jit_extr_d(JIT_F1, JIT_R0);
	    goto float_cmp;
	case lf32|rf32:		case lf32|rf64:
	case lf64|rf32:		case lf64|rf64:
	    switch (lcode) {
		case eop_noop:
		    maybe_reload_freg_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_freg_reg_type(lbase, lvoff, JIT_F0, JIT_F0, t_float);
		    load_freg(lbase, lvoff);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_freg_reg_type(lbase, lvoff, JIT_F0, JIT_F0, ltype);
		    if (lkind & lf32)
			jit_extr_f_d(JIT_F0, JIT_F0);
		    break;
		default:
		    abort();
	    }
	    if (same)
		jit_movr_d(JIT_F1, JIT_F0);
	    else {
		switch (rcode) {
		    case eop_ld:	case eop_lb:
			load_freg_reg_type(rbase, rvoff,
					   JIT_F1, JIT_F1, t_float);
			break;
		    case eop_ldt:	case eop_lbt:	case eop_lc:
			load_freg_reg_type(rbase, rvoff, JIT_F1, JIT_F1, rtype);
			if (rkind & rf32)
			    jit_extr_f_d(JIT_F1, JIT_F1);
			break;
		    default:
			abort();
		}
	    }
	float_cmp:
	    switch (code) {
		case eop_lt:	jump = jit_bltr_d(JIT_F0, JIT_F1);	break;
		case eop_le:	jump = jit_bler_d(JIT_F0, JIT_F1);	break;
		case eop_eq:	jump = jit_beqr_d(JIT_F0, JIT_F1);	break;
		case eop_ge:	jump = jit_bger_d(JIT_F0, JIT_F1);	break;
		case eop_gt:	jump = jit_bgtr_d(JIT_F0, JIT_F1);	break;
		default:	jump = jit_bner_d(JIT_F0, JIT_F1);	break;
	    }
	    if (index >= 0)		jit_patch_at(jump, labels[index]);
	    else			record_forward_patch(jump, -index);
	    if (lnext || rnext) {
		assert(done == null);
		done = jit_forward();
		jump = jit_jmpi();
		jit_patch_at(jump, done);
		goto fallback;
	    }
	    break;
	default:
	    if (doint || doflt) {
		done = jit_forward();
		fail = jit_forward();
		jump = null;
		switch (lcode) {
		    case eop_noop:
			emit_sync();
			break;
		    case eop_ld:
			jump = jit_beqi(lbase, 0);
			break;
		    case eop_lc:
			if (lcdyn) {
			    assert(!(lkind & ~(lint|lrel)));
			    jump = jit_beqi(lbase, 0);
			}
			break;
		    default:
			break;
		}
		if (jump)
		    jit_patch_at(jump, fail);
		if (!same) {
		    jump = null;
		    switch (rcode) {
			case eop_ld:
			    jump = jit_beqi(rbase, 0);
			    break;
			case eop_lc:
			    if (rcdyn) {
				assert(!(rkind & ~(rint|rrel)));
				jump = jit_beqi(rbase, 0);
			    }
			    break;
			default:
			    break;
		    }
		    if (jump)
			jit_patch_at(jump, fail);
		}
	    }
	    if (doint) {
		if (lkind & lint) {
		    switch (lcode) {
			case eop_noop:	case eop_ld:	case eop_lb:
			case eop_lc:
			    jit_ldxi_i(JIT_R0, lbase, ltoff);
			    break;
			default:
			    abort();
		    }
		    lnext = jit_bnei(JIT_R0, t_int);
		}
		switch (lcode) {
		    case eop_noop:
			maybe_reload_ireg_implicit();
			break;
		    case eop_ld:	case eop_lb:
		    left_int_dynamic:
			load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, t_int);
			break;
		    case eop_ldt:	case eop_lbt:
		    left_int_static:
			load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, ltype);
			zero_sign_extend_reg(ltype, JIT_V1, JIT_V2);
			break;
		    case eop_lc:
			if (lcdyn)	goto left_int_dynamic;
			goto left_int_static;
		    default:
			abort();
		}
		if (lkind & lu64) {
#  if __WORDSIZE == 32
		    jump = jit_blti(JIT_V2, 0);
#  else
		    jump = jit_blti(JIT_V1, 0);
#  endif
		    jit_patch_at(jump, fail);
		}
		if (same) {
		    jit_movr(JIT_R0, JIT_V1);
#  if __WORDSIZE == 32
		    jit_movr(JIT_R2, JIT_V2);
#  endif
		}
		else {
		    jext = null;
		    if (rkind & (rint|rrel)) {
			switch (rcode) {
			    case eop_noop:	case eop_ld:	case eop_lb:
			    case eop_lc:
				jit_ldxi_i(JIT_R0, rbase, rtoff);
				break;
			    default:
				abort();
			}
			if (
#  if __WORDSIZE == 32
			    (lkind == li32) &&
#  endif
			    (rkind & rrel)) {
			    jext = jit_beqi(JIT_R0, t_int);
			    jump = jit_bnei(JIT_R0, t_float);
			    jit_patch_at(jump, fail);
			}
			else
			    rnext = jit_bnei(JIT_R0, t_int);
		    }
		    if (
#  if __WORDSIZE == 32
			(lkind == li32) &&
#  endif
			(rkind & (rf32|rf64|rrel))) {
			switch (rcode) {
			    case eop_ld:	case eop_lb:
			    right_float_ext_dynamic:
				load_freg_reg_type(rbase, rvoff,
						   JIT_F1, JIT_F1, t_float);
				break;
			    case eop_ldt:	case eop_lbt:
			    right_float_ext_static:
				load_freg_reg_type(rbase, rvoff,
						   JIT_F1, JIT_F1, rtype);
				if (rkind & rf32)
				    jit_extr_f_d(JIT_F1, JIT_F1);
				break;
			    case eop_lc:
				if (rcdyn)	goto right_float_ext_dynamic;
				goto right_float_ext_static;
			    default:
				abort();
			}
			jit_extr_d(JIT_F0, JIT_V1);
			switch (code) {
			    case eop_lt:
				jump = jit_bltr_d(JIT_F0, JIT_F1);	break;
			    case eop_le:
				jump = jit_bler_d(JIT_F0, JIT_F1);	break;
			    case eop_eq:
				jump = jit_beqr_d(JIT_F0, JIT_F1);	break;
			    case eop_ge:
				jump = jit_bger_d(JIT_F0, JIT_F1);	break;
			    case eop_gt:
				jump = jit_bgtr_d(JIT_F0, JIT_F1);	break;
			    default:
				jump = jit_bner_d(JIT_F0, JIT_F1);	break;
			}
			if (index >= 0)
			    jit_patch_at(jump, labels[index]);
			else
			    record_forward_patch(jump, -index);
			jump = jit_jmpi();
			jit_patch_at(jump, done);
		    }
		    if (jext)
			jit_patch(jext);
		    switch (rcode) {
			case eop_ld:	case eop_lb:
			right_int_dynamic:
			    load_ireg_reg_type(rbase, rvoff,
					       JIT_R0, JIT_R2, t_int);
			    break;
			case eop_ldt:	case eop_lbt:
			right_int_static:
			    load_ireg_reg_type(rbase, rvoff,
					       JIT_R0, JIT_R2, rtype);
			    zero_sign_extend_reg(rtype, JIT_R0, JIT_R2);
			    break;
			case eop_lc:
			    if (rcdyn)	goto right_int_dynamic;
			    goto right_int_static;
			default:
			    abort();
		    }
		    if (rkind & ru64) {
#  if __WORDSIZE == 32
			jump = jit_blti(JIT_R2, 0);
#  else
			jump = jit_blti(JIT_R0, 0);
#  endif
			jit_patch_at(jump, fail);
		    }
		}
#  if __WORDSIZE == 32
		switch (code) {
		    case eop_lt:
			jump = jit_bltr(JIT_V2, JIT_R2);
			temp = jit_bgtr(JIT_V2, JIT_R2);
			if (index >= 0)	jit_patch_at(jump, labels[index]);
			else		record_forward_patch(jump, -index);
			jump = jit_bltr_u(JIT_V1, JIT_R0);
			jit_patch(temp);
			break;
		    case eop_le:
			jump = jit_bgtr(JIT_R2, JIT_V2);
			temp = jit_bltr(JIT_R2, JIT_V2);
			if (index >= 0)	jit_patch_at(jump, labels[index]);
			else		record_forward_patch(jump, -index);
			jump = jit_bler_u(JIT_V1, JIT_R0);
			jit_patch(temp);
			break;
		    case eop_eq:
			temp = jit_bner(JIT_V1, JIT_R0);
			jump = jit_beqr(JIT_V2, JIT_R2);
			jit_patch(temp);
			break;
		    case eop_ge:
			jump = jit_bltr(JIT_R2, JIT_V2);
			temp = jit_bgtr(JIT_R2, JIT_V2);
			if (index >= 0)	jit_patch_at(jump, labels[index]);
			else		record_forward_patch(jump, -index);
			jump = jit_bger_u(JIT_V1, JIT_R0);
			jit_patch(temp);
			break;
		    case eop_gt:
			jump = jit_bgtr(JIT_V2, JIT_R2);
			temp = jit_bltr(JIT_V2, JIT_R2);
			if (index >= 0)	jit_patch_at(jump, labels[index]);
			else		record_forward_patch(jump, -index);
			jump = jit_bgtr_u(JIT_V1, JIT_R0);
			jit_patch(temp);
			break;
		    default:
			jump = jit_bner(JIT_V1, JIT_R0);
			if (index >= 0)	jit_patch_at(jump, labels[index]);
			else		record_forward_patch(jump, -index);
			jump = jit_bner(JIT_V2, JIT_R2);
			break;
		}
#  else
		switch (code) {
		    case eop_lt:jump = jit_bltr(JIT_V1, JIT_R0);	break;
		    case eop_le:jump = jit_bler(JIT_V1, JIT_R0);	break;
		    case eop_eq:jump = jit_beqr(JIT_V1, JIT_R0);	break;
		    case eop_ge:jump = jit_bger(JIT_V1, JIT_R0);	break;
		    case eop_gt:jump = jit_bgtr(JIT_V1, JIT_R0);	break;
		    default:	jump = jit_bner(JIT_V1, JIT_R0);	break;
		}
#  endif
		if (index >= 0)	jit_patch_at(jump, labels[index]);
		else		record_forward_patch(jump, -index);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (doflt) {
		if (lnext) {
		    jit_patch(lnext);
		    lnext = null;
		}
		if (rnext) {
		    jit_patch(rnext);
		    rnext = null;
		}
		if (lkind & lrel) {
		    if (lnext == null || rnext != null) {
			switch (lcode) {
			    case eop_noop:	case eop_ld:	case eop_lb:
			    case eop_lc:
				jit_ldxi_i(JIT_R0, lbase, ltoff);
				break;
			    default:
				abort();
			}
		    }
		    lnext = jit_bnei(JIT_R0, t_float);
		}
		switch (lcode) {
		    case eop_noop:
			maybe_reload_freg_implicit();
			break;
		    case eop_ld:	case eop_lb:
		    left_float_dynamic:
			load_freg_reg_type(lbase, lvoff,
					   JIT_F0, JIT_F0, t_float);
			break;
		    case eop_ldt:	case eop_lbt:
		    left_float_static:
			load_freg_reg_type(lbase, lvoff,
					   JIT_F0, JIT_F0, ltype);
			if (lkind & lf32)
			    jit_extr_f_d(JIT_F0, JIT_F0);
			break;
		    case eop_lc:
			if (lcdyn)	goto left_float_dynamic;
			goto left_float_static;
		    default:
			abort();
		}
		/* set if generating code to convert int to float */
		jcvt = null;
		if (same)
		    jit_movr_d(JIT_F1, JIT_F0);
		else {
		    jext = null;
		    if (rkind & (rint|rrel)) {
			switch (rcode) {
			    case eop_noop:	case eop_ld:	case eop_lb:
			    case eop_lc:
				jit_ldxi_i(JIT_R0, rbase, rtoff);
				break;
			    default:
				abort();
			}
#  if __WORDSIZE == 64
			if (rkind & rint) {
			    jext = jit_beqi(JIT_R0, t_float);
			    jump = jit_bnei(JIT_R0, t_int);
			    jit_patch_at(jump, fail);
			}
			else
#  endif
			    rnext = jit_bnei(JIT_R0, t_float);
		    }
		    if (
#  if __WORDSIZE == 32
			(rkind == ri32)
#  else
			(rkind & (ri32|ri64|ru64|rint))
#  endif
			) {
			switch (rcode) {
			    case eop_ld:	case eop_lb:
			    right_int_ext_dynamic:
				load_ireg_reg_type(rbase, rvoff,
						   JIT_R0, JIT_R2, t_int);
				break;
			    case eop_ldt:	case eop_lbt:
			    right_int_ext_static:
				load_ireg_reg_type(rbase, rvoff,
						   JIT_R0, JIT_R2, rtype);
				zero_sign_extend_reg(rtype, JIT_R0, JIT_R2);
				break;
			    case eop_lc:
				if (rcdyn)	goto right_int_ext_dynamic;
				goto right_int_ext_static;
			    default:
				abort();
			}
#  if __WORDSIZE == 64
			if (rkind & ru64) {
			    jump = jit_blti(JIT_R0, 0);
			    jit_patch_at(jump, fail);
			}
#  endif
			jit_extr_d(JIT_F1, JIT_R0);
			jcvt = jit_jmpi();
		    }
		    if (jext)
			jit_patch(jext);
		    switch (rcode) {
			case eop_ld:	case eop_lb:
			right_float_dynamic:
			    load_freg_reg_type(rbase, rvoff,
					       JIT_F1, JIT_F1, t_float);
			    break;
			case eop_ldt:	case eop_lbt:
			right_float_static:
			    load_freg_reg_type(rbase, rvoff,
					       JIT_F1, JIT_F1, rtype);
			    if (rkind & rf32)
				jit_extr_f_d(JIT_F1, JIT_F1);
			    break;
			case eop_lc:
			    if (rcdyn)	goto right_float_dynamic;
			    goto right_float_static;
			default:
			    abort();
		    }
		}
		/* if did convert int to float */
		if (jcvt)
		    jit_patch(jcvt);
		switch (code) {
		    case eop_lt:jump = jit_bltr_d(JIT_F0, JIT_F1);	break;
		    case eop_le:jump = jit_bler_d(JIT_F0, JIT_F1);	break;
		    case eop_eq:jump = jit_beqr_d(JIT_F0, JIT_F1);	break;
		    case eop_ge:jump = jit_bger_d(JIT_F0, JIT_F1);	break;
		    case eop_gt:jump = jit_bgtr_d(JIT_F0, JIT_F1);	break;
		    default:	jump = jit_bner_d(JIT_F0, JIT_F1);	break;
		}
		if (index >= 0)		jit_patch_at(jump, labels[index]);
		else			record_forward_patch(jump, -index);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	fallback:
	    if (fail)
		jit_link(fail);
	    if (lnext)
		jit_patch(lnext);
	    if (rnext)
		jit_patch(rnext);
	    switch (lcode) {
		case eop_noop:						break;
		case eop_ld:	call_vi(evm_ld, lsoff);			break;
		case eop_ldt:	call_vii(evm_ldt, lsoff, ltype);	break;
		case eop_lb:	call_vi(evm_lb, lsoff);			break;
		case eop_lbt:	call_vii(evm_lbt, lsoff, ltype);	break;
		case eop_lc:	call_vii(evm_lc, lsoff, ltype);		break;
		default:	abort();
	    }
	    jit_calli(evm_push);
	    if (!same) {
		switch (rcode) {
		    case eop_noop:					break;
		    case eop_ld:	call_vi(evm_ld, rsoff);		break;
		    case eop_ldt:	call_vii(evm_ldt, rsoff, rtype);break;
		    case eop_lb:	call_vi(evm_lb, rsoff);		break;
		    case eop_lbt:	call_vii(evm_lbt, rsoff, rtype);break;
		    case eop_lc:	call_vii(evm_lc, rsoff, rtype);	break;
		    default:	abort();
		}
	    }
	    switch (code) {
		case eop_ne:	jit_calli(evm_ne);			break;
		case eop_lt:	jit_calli(evm_lt);			break;
		case eop_le:	jit_calli(evm_le);			break;
		case eop_eq:	jit_calli(evm_eq);			break;
		case eop_ge:	jit_calli(evm_ge);			break;
		default:	jit_calli(evm_gt);			break;
	    }
	    load_ireg32_implicit();
	    jump = jit_bnei(JIT_V1, 0);
	    if (index >= 0)	jit_patch_at(jump, labels[index]);
	    else		record_forward_patch(jump, -index);
	    if (done)
		jit_link(done);
	    break;
    }
    emit_clear();
}

static void
emit_load_push_load_addsub(east_list_t *ast0, east_list_t *ast1,
			   east_list_t *ast2, east_list_t *ast3)
{
    ebool_t		 same;
    jit_node_t		*done,  *fail;
    jit_node_t		*jcvt,  *jext;
    jit_node_t		*jump,  *next;
    jit_node_t		*lnext, *rnext;
    ecode_t		 lcode,  rcode;
    etype_t		 ltype,  rtype;
    eint32_t		 lsoff,  rsoff;
    eint32_t		 ltoff,  rtoff;
    eint32_t		 lvoff,  rvoff;
    eint32_t		 lcdyn,  rcdyn;
    jit_int32_t		 lbase,  rbase;
    ebool_t		 doint,  doflt;
    eint32_t		 lkind,  rkind, ikind;

    lbase = rbase = JIT_R1;
    done = fail = lnext = rnext = null;
    doint = doflt = lcdyn = rcdyn = false;
    if (ast0) {
	lkind = ast0->itype;
	ltype = east_node(ast0)->csymbol.symbol->type;
	lsoff = east_node(ast0)->csymbol.symbol->offset;
	switch (lcode = east_node(ast0)->code) {
	    case eop_ld:	case eop_ldt:
		ltoff = -4;	lvoff = 0;
		break;
	    case eop_lb:	case eop_lbt:
		ltoff = lsoff * sizeof(evalue_t) + offsetof(evalue_t, t);
		lvoff = lsoff * sizeof(evalue_t) + offsetof(evalue_t, v.o);
		break;
	    case eop_lc:
		ltoff = -4;	lvoff = lsoff;
		lcdyn = ltype == t_void || ltype > elast_basic_type;
		break;
	    default:
		abort();
	}
    }
    else {
	lkind = ltype = ast1->rtype;
	lsoff = 0;
	lcode = eop_noop;
	ltoff = offsetof(ethread_t, r0) + offsetof(evalue_t, t);
	lvoff = offsetof(ethread_t, r0) + offsetof(evalue_t, v.o);
    }
    switch (lkind) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    lkind = li32;		break;
	case t_uint32:	case t_int:
	    lkind = li64;		break;
	case t_uint:
	    lkind = lu64;		break;
	case t_exact:
	    lkind = lint;		break;
	case t_float32:
	    lkind = lf32;		break;
	case t_float:
	    lkind = lf64;		break;
	case t_inexact:
	    lkind = lrel;		break;
	case t_dynamic:
	    lkind = lint|lrel;		break;
	default:
	    lkind = 0;			break;
    }
    if ((same = (ast2 == null ||
		 (ast0 && east_node(ast0)->code == east_node(ast2)->code &&
		  east_node(ast0)->csymbol.symbol ==
		  east_node(ast2)->csymbol.symbol)))) {
	rkind = lkind >> 8;	rtype = ltype;		rsoff = lsoff;
	rcode = lcode;		rtoff = ltoff;		rvoff = lvoff;
	rcdyn = lcdyn;
    }
    else {
	rkind = ast2->itype;
	rtype = east_node(ast2)->csymbol.symbol->type;
	rsoff = east_node(ast2)->csymbol.symbol->offset;
	switch (rcode = east_node(ast2)->code) {
	    case eop_ld:	case eop_ldt:
		rtoff = -4;	rvoff = 0;
		break;
	    case eop_lb:	case eop_lbt:
		rtoff = rsoff * sizeof(evalue_t) + offsetof(evalue_t, t);
		rvoff = rsoff * sizeof(evalue_t) + offsetof(evalue_t, v.o);
		break;
	    case eop_lc:
		rtoff = -4;	rvoff = rsoff;
		rcdyn = rtype == t_void || rtype > elast_basic_type;
		break;
	    default:
		abort();
	}
	switch (rkind) {
	    case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	    case t_int32:
		rkind = ri32;		break;
	    case t_uint32:	case t_int:
		rkind = ri64;		break;
	    case t_uint:
		rkind = ru64;		break;
	    case t_exact:
		rkind = rint;		break;
	    case t_float32:
		rkind = rf32;		break;
	    case t_float:
		rkind = rf64;		break;
	    case t_inexact:
		rkind = rrel;		break;
	    case t_dynamic:
		rkind = rint|rrel;	break;
	    default:
		rkind = 0;		break;
	}
    }
    switch (ast3->itype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    ikind = ii32;		break;
	case t_uint32:	case t_int:
	    ikind = ii64;		break;
	case t_exact:
	    ikind = iint;		break;
	case t_float:
	    ikind = if64;		break;
	case t_inexact:
	    ikind = irel;		break;
	case t_dynamic:
	    ikind = iint|irel;		break;
	default:
	    ikind = 0;			break;
    }
#  if __WORDSIZE == 32
    switch (lkind|rkind) {
	case lf32|ri64:		case lf32|ru64:		case lf32|rint:
	case lf64|ri64:		case lf64|ru64:		case lf64|rint:
	case lrel|ri64:		case lrel|ru64:		case lrel|rint:
	case li64|rf32:		case li64|rf64:		case li64|rrel:
	case lu64|rf32:		case lu64|rf64:		case lu64|rrel:
	case lint|rf32:		case lint|rf64:		case lint|rrel:
	    lkind = rkind = 0;
	    if (lcode == eop_noop)
		emit_sync();
	    break;
	case lint|lrel|rf32:	case lint|lrel|rf64:	case lint|lrel|rrel:
	    lkind &= ~lint;
	    break;
	case lf32|rint|rrel:	case lf64|rint|rrel:	case lrel|rint|rrel:
	    rkind &= ~rint;
	    break;
	default:
	    break;
    }
#  endif
    if (lkind & (li32|li64|lu64|lint)) {
	if (rkind & (ri32|ri64|ru64|rint))
	    doint = true;
	else if (
#  if __WORDSIZE == 32
		 lkind == li32 &&
#  endif
		 (rkind & (rf32|rf64|rrel)))
	    doint = true;
    }
    if (lkind & (lf32|lf64|lrel)) {
	if (rkind & (rf32|rf64|rrel))
	    doflt = true;
	else if (
#  if __WORDSIZE == 32
		 rkind == ri32
#  else
		 rkind & (ri32|ri64|ru64|rint)
#  endif
		 )
	    doflt = true;
    }
    if (doint || doflt) {
	switch (lcode) {
	    case eop_noop:
		lbase = JIT_V0;
		break;
	    case eop_ld:		case eop_ldt:
		lbase = JIT_R1;
		jit_ldi(lbase, (jit_word_t)
			((eint8_t *)eds + lsoff * sizeof(eobject_t)));
		break;
	    case eop_lb:	case eop_lbt:
		lbase = JIT_R1;
		jit_ldxi(lbase, JIT_V0, offsetof(ethread_t, ebp));
		break;
	    case eop_lc:
		lbase = JIT_R1;
		jit_ldxi(lbase, JIT_V0, offsetof(ethread_t, ebp));
		switch (rcode) {
		    case eop_noop:	case eop_ld:	case eop_ldt:
		    case eop_lc:
			jit_ldxi(lbase, lbase,
				 -2 * sizeof(evalue_t) +
				 offsetof(evalue_t, v.o));
			break;
		    case eop_lb:	case eop_lbt:
			/* cannot be same */
			rbase = JIT_R1;	lbase = JIT_R2;
			jit_ldxi(lbase, rbase,
				 -2 * sizeof(evalue_t) +
				 offsetof(evalue_t, v.o));
			break;
		    default:
			abort();
		}
		break;
	    default:
		abort();
	}
	if (same) {
	    rbase = lbase;
	    if (lcdyn) {
		jit_ldxi(lbase, lbase, lvoff);
		lvoff = rvoff = 0;
	    }
	}
	else {
	    switch (rcode) {
		case eop_ld:	case eop_ldt:
		    rbase = JIT_R2;
		    jit_ldi(rbase, (jit_word_t)
			    ((eint8_t *)eds + rsoff * sizeof(eobject_t)));
		    break;
		case eop_lb:	case eop_lbt:
		    switch (lcode) {
			case eop_noop:
			    rbase = JIT_R1;
			    jit_ldxi(rbase, JIT_V0, offsetof(ethread_t, ebp));
			    break;
			case eop_ld:	case eop_ldt:
			    rbase = JIT_R2;
			    jit_ldxi(rbase, JIT_V0, offsetof(ethread_t, ebp));
			    break;
			case eop_lb:	case eop_lbt:
			    rbase = lbase;
			    break;
			case eop_lc:
			    /* rbase already set */
			    break;
			default:
			    abort();
		    }
		    break;
		case eop_lc:
		    switch (lcode) {
			case eop_noop:
			    rbase = JIT_R1;
			    goto load_class_second;
			case eop_ld:	case eop_ldt:
			    rbase = JIT_R2;
			load_class_second:
			    jit_ldxi(rbase, JIT_V0, offsetof(ethread_t, ebp));
			    jit_ldxi(rbase, rbase,
				     -2 * sizeof(evalue_t) +
				     offsetof(evalue_t, v.o));
			    break;
			case eop_lb:	case eop_lbt:
			    rbase = JIT_R2;
			    jit_ldxi(rbase, lbase,
				     -2 * sizeof(evalue_t) +
				     offsetof(evalue_t, v.o));
			    break;
			case eop_lc:
			    rbase = lbase;
			    break;
			default:
			    abort();
		    }
		    break;
		default:
		    abort();
	    }
	    if (rcdyn) {
		jit_ldxi(JIT_R2, rbase, rvoff);
		rbase = JIT_R2;
		rvoff = 0;
	    }
	    if (lcdyn) {
		jit_ldxi(lbase, lbase, lvoff);
		lvoff = 0;
	    }
	}
    }
    switch (lkind|rkind|ikind) {
	case li32|ri32|ii32:
	    switch (lcode) {
		case eop_noop:
		    maybe_reload_ireg32_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, t_int32);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, ltype);
		    break;
		default:
		    abort();
	    }
	    if (same)
		jit_movr(JIT_R0, JIT_V1);
	    else {
		switch (rcode) {
		    case eop_ld:	case eop_lb:
			load_ireg_reg_type(rbase, rvoff,
					   JIT_R0, JIT_R2, t_int32);
			break;
		    case eop_ldt:	case eop_lbt:	case eop_lc:
			load_ireg_reg_type(rbase, rvoff, JIT_R0, JIT_R2, rtype);
			break;
		    default:
			abort();
		}
	    }
	    if (east_node(ast3)->code == eop_add)
		jit_addr(JIT_V1, JIT_V1, JIT_R0);
	    else
		jit_subr(JIT_V1, JIT_V1, JIT_R0);
	    ejit_sync = ejit_sync_register;
	    break;
	case li32|ri32|ii64:	case li32|ri64|ii64:
	case li64|ri32|ii64:	case li64|ri64|ii64:
	    switch (lcode) {
		case eop_noop:
		    maybe_reload_ireg_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, t_int);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, ltype);
		    zero_sign_extend_reg(ltype, JIT_V1, JIT_V2);
		    break;
		default:
		    abort();
	    }
	    if (same) {
		jit_movr(JIT_R0, JIT_V1);
#  if __WORDSIZE == 32
		jit_movr(JIT_R2, JIT_V2);
#  endif
	    }
	    else {
		switch (rcode) {
		    case eop_ld:	case eop_lb:
			load_ireg_reg_type(rbase, rvoff, JIT_R0, JIT_R2, t_int);
			break;
		    case eop_ldt:	case eop_lbt:	case eop_lc:
			load_ireg_reg_type(rbase, rvoff, JIT_R0, JIT_R2, rtype);
			zero_sign_extend_reg(rtype, JIT_R0, JIT_R2);
			break;
		    default:
			abort();
		}
	    }
#  if __WORDSIZE == 32
	    if (east_node(ast3)->code == eop_add) {
		jit_addcr(JIT_V1, JIT_V1, JIT_R0);
		jit_addxr(JIT_V2, JIT_V2, JIT_R2);
	    }
	    else {
		jit_subcr(JIT_V1, JIT_V1, JIT_R0);
		jit_subxr(JIT_V2, JIT_V2, JIT_R2);
	    }
#  else
	    if (east_node(ast3)->code == eop_add)
		jit_addr(JIT_V1, JIT_V1, JIT_R0);
	    else
		jit_subr(JIT_V1, JIT_V1, JIT_R0);
#  endif
	    ejit_sync = ejit_sync_register|ejit_sync_int_ext;
	    break;
	case li32|ri32|iint:	case li32|ri64|iint:	case li32|ru64|iint:
	case li64|ri32|iint:	case li64|ri64|iint:	case li64|ru64|iint:
	case lu64|ri32|iint:	case lu64|ri64|iint:	case lu64|ru64|iint:
	    done = jit_forward();
	    fail = jit_forward();
	    switch (lcode) {
		case eop_noop:
		    if (!(ejit_sync & ejit_sync_register)) {
			assert(ejit_sync & ejit_sync_implicit);
			load_ireg_implicit();
		    }
		    else {
			if (!(ejit_sync & ejit_sync_int_ext))
			    zero_sign_extend(ltype);
			if (!(ejit_sync & ejit_sync_implicit))
			    store_ireg_implicit(true);
		    }
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, t_int);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, ltype);
		    zero_sign_extend_reg(ltype, JIT_V1, JIT_V2);
		    break;
		default:
		    abort();
	    }
	    if (lkind & lu64) {
#  if __WORDSIZE == 32
		jump = jit_blti(JIT_V2, 0);
#  else
		jump = jit_blti(JIT_V1, 0);
#  endif
		jit_patch_at(jump, fail);
	    }
	    if (same) {
		jit_movr(JIT_R0, JIT_V1);
#  if __WORDSIZE == 32
		jit_movr(JIT_R2, JIT_V2);
#  endif
	    }
	    else {
		switch (rcode) {
		    case eop_ld:	case eop_lb:
			load_ireg_reg_type(rbase, rvoff, JIT_R0, JIT_R2, t_int);
			break;
		    case eop_ldt:	case eop_lbt:	case eop_lc:
			load_ireg_reg_type(rbase, rvoff, JIT_R0, JIT_R2, rtype);
			zero_sign_extend_reg(rtype, JIT_R0, JIT_R2);
			break;
		    default:
			abort();
		}
		if (rkind & ru64) {
#  if __WORDSIZE == 32
		    jump = jit_blti(JIT_R2, 0);
#  else
		    jump = jit_blti(JIT_R0, 0);
#  endif
		    jit_patch_at(jump, fail);
		}
	    }
#  if __WORDSIZE == 32
	    jit_movr(JIT_R1, JIT_V1);
	    if (east_node(ast3)->code == eop_add) {
		jit_addr(JIT_V1, JIT_V1, JIT_R0);
		jit_ltr_u(JIT_R0, JIT_V1, JIT_R1);
	    }
	    else {
		jit_subr(JIT_V1, JIT_V1, JIT_R0);
		jit_gtr_u(JIT_R0, JIT_V1, JIT_R1);
	    }
	    jump = jit_boaddr(JIT_R2, JIT_R0);
	    jit_patch_at(jump, fail);
	    if (east_node(ast3)->code == eop_add)
		jump = jit_boaddr(JIT_V2, JIT_R2);
	    else
		jump = jit_bosubr(JIT_V2, JIT_R2);
#  else
	    if (east_node(ast3)->code == eop_add)
		jump = jit_boaddr(JIT_V1, JIT_R0);
	    else
		jump = jit_bosubr(JIT_V1, JIT_R0);
#  endif
	    jit_patch_at(jump, fail);
	    store_ireg_implicit(lcode != eop_noop);
	    jump = jit_jmpi();
	    jit_patch_at(jump, done);
	    goto fallback;
	case li32|rf32|if64:	case li32|rf64|if64:
#  if __WORDSIZE == 64
	case li64|rf32|if64:	case li64|rf64|if64:
	case lu64|rf32|if64:	case lu64|rf64|if64:
#  endif
	    switch (lcode) {
		case eop_noop:
		    if (lkind & lu64) {
			if (!(ejit_sync & ejit_sync_register))
			    load_ireg_implicit();
			else
			    store_ireg_implicit(true);
		    }
		    else
			maybe_reload_ireg_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, t_int);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, ltype);
		    break;
		default:
		    abort();
	    }
	    if (lkind & lu64) {
		done = jit_forward();
		lnext = jit_blti(JIT_V1, 0);
	    }
	    jit_extr_d(JIT_F0, JIT_V1);
	    switch (rcode) {
		case eop_ld:	case eop_lb:
		    load_freg_reg_type(rbase, rvoff, JIT_F1, JIT_F1, t_float);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_freg_reg_type(rbase, rvoff, JIT_F1, JIT_F1, rtype);
		    if (rkind & rf32)
			jit_extr_f_d(JIT_F1, JIT_F1);
		    break;
		default:
		    abort();
	    }
	    if (east_node(ast3)->code == eop_add)
		jit_addr_d(JIT_F0, JIT_F0, JIT_F1);
	    else
		jit_subr_d(JIT_F0, JIT_F0, JIT_F1);
	    if (lkind & lu64) {
		store_freg_implicit(true);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
		goto fallback;
	    }
	    ejit_sync = ejit_sync_register;
	    break;
	case lf32|ri32|if64:	case lf64|ri32|if64:
#  if __WORDSIZE == 64
	case lf32|ri64|if64:	case lf64|ri64|if64:
	case lf32|ru64|if64:	case lf64|ru64|if64:
#  endif
	    switch (lcode) {
		case eop_noop:
		    if (!(ejit_sync & ejit_sync_register)) {
			assert(ejit_sync & ejit_sync_implicit);
			load_freg_implicit();
		    }
		    else {
			if ((lkind & lf32) &&
			    !(ejit_sync & ejit_sync_float_ext))
			    jit_extr_f_d(JIT_F0, JIT_F1);
			if (rkind & ru64)
			    store_freg_implicit(true);
		    }
		    break;
		case eop_ld:	case eop_lb:
		    load_freg_reg_type(lbase, lvoff, JIT_F0, JIT_F0, t_float);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_freg_reg_type(lbase, lvoff, JIT_F0, JIT_F0, ltype);
		    if (lkind & lf32)
			jit_extr_f_d(JIT_F0, JIT_F0);
		    break;
		default:
		    abort();
	    }
	    switch (rcode) {
		case eop_ld:	case eop_lb:
		    load_ireg_reg_type(rbase, rvoff, JIT_R0, JIT_R2, t_int);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_reg_type(rbase, rvoff, JIT_R0, JIT_R2, rtype);
		    break;
		default:
		    abort();
	    }
	    if (rkind & ru64) {
		done = jit_forward();
		rnext = jit_blti(JIT_R0, 0);
	    }
	    jit_extr_d(JIT_F1, JIT_R0);
	    if (east_node(ast3)->code == eop_add)
		jit_addr_d(JIT_F0, JIT_F0, JIT_F1);
	    else
		jit_subr_d(JIT_F0, JIT_F0, JIT_F1);
	    if (rkind & ru64) {
		store_freg_implicit(lcode != eop_noop);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
		goto fallback;
	    }
	    ejit_sync = ejit_sync_register;
	    break;
	case lf32|rf32|if64:	case lf32|rf64|if64:
	case lf64|rf32|if64:	case lf64|rf64|if64:
	    switch (lcode) {
		case eop_noop:
		    if (lkind & lf32) {
			if (!(ejit_sync & ejit_sync_register)) {
			    assert(ejit_sync & ejit_sync_implicit);
			    load_freg_implicit();
			}
			else if (!(ejit_sync & ejit_sync_float_ext))
			    jit_extr_f_d(JIT_F0, JIT_F1);
		    }
		    else
			maybe_reload_freg_implicit();
		    break;
		case eop_ld:	case eop_lb:
		    load_freg_reg_type(lbase, lvoff, JIT_F0, JIT_F0, t_float);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_freg_reg_type(lbase, lvoff, JIT_F0, JIT_F0, ltype);
		    if (lkind & lf32)
			jit_extr_f_d(JIT_F0, JIT_F0);
		    break;
		default:
		    abort();
	    }
	    if (same)
		jit_movr_d(JIT_F1, JIT_F0);
	    else {
		switch (rcode) {
		    case eop_ld:	case eop_lb:
			load_freg_reg_type(rbase, rvoff,
					   JIT_R0, JIT_R2, t_float);
			break;
		    case eop_ldt:	case eop_lbt:	case eop_lc:
			load_freg_reg_type(rbase, rvoff, JIT_F1, JIT_F1, rtype);
			if (rkind & rf32)
			    jit_extr_f_d(JIT_F1, JIT_F1);
			break;
		    default:
			abort();
		}
	    }
	    if (east_node(ast3)->code == eop_add)
		jit_addr_d(JIT_F0, JIT_F0, JIT_F1);
	    else
		jit_subr_d(JIT_F0, JIT_F0, JIT_F1);
	    ejit_sync = ejit_sync_register;
	    break;
	default:
	    if (doint || doflt) {
		done = jit_forward();
		fail = jit_forward();
		jump = null;
		switch (lcode) {
		    case eop_noop:
			emit_sync();
			break;
		    case eop_ld:
			jump = jit_beqi(lbase, 0);
			break;
		    case eop_lc:
			if (lcdyn) {
			    assert(!(lkind & ~(lint|lrel)));
			    jump = jit_beqi(lbase, 0);
			}
			break;
		    default:
			break;
		}
		if (jump)
		    jit_patch_at(jump, fail);
		if (!same) {
		    jump = null;
		    switch (rcode) {
			case eop_ld:
			    jump = jit_beqi(rbase, 0);
			    break;
			case eop_lc:
			    if (rcdyn) {
				assert(!(rkind & ~(rint|rrel)));
				jump = jit_beqi(rbase, 0);
			    }
			    break;
			default:
			    break;
		    }
		    if (jump)
			jit_patch_at(jump, fail);
		}
	    }
	    if (doint) {
		if (lkind & lint) {
		    switch (lcode) {
			case eop_noop:	case eop_ld:	case eop_lb:
			case eop_lc:
			    jit_ldxi_i(JIT_R0, lbase, ltoff);
			    break;
			default:
			    abort();
		    }
		    lnext = jit_bnei(JIT_R0, t_int);
		}
		switch (lcode) {
		    case eop_noop:
			maybe_reload_ireg_implicit();
			break;
		    case eop_ld:	case eop_lb:
		    left_int_dynamic:
			load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, t_int);
			break;
		    case eop_ldt:	case eop_lbt:
		    left_int_static:
			load_ireg_reg_type(lbase, lvoff, JIT_V1, JIT_V2, ltype);
			zero_sign_extend_reg(ltype, JIT_V1, JIT_V2);
			break;
		    case eop_lc:
			if (lcdyn)	goto left_int_dynamic;
			goto left_int_static;
		    default:
			abort();
		}
		if (lkind & lu64) {
#  if __WORDSIZE == 32
		    jump = jit_blti(JIT_V2, 0);
#  else
		    jump = jit_blti(JIT_V1, 0);
#  endif
		    jit_patch_at(jump, fail);
		}
		if (same) {
		    jit_movr(JIT_R0, JIT_V1);
#  if __WORDSIZE == 32
		    jit_movr(JIT_R2, JIT_V2);
#  endif
		}
		else {
		    jext = null;
		    if (rkind & (rint|rrel)) {
			switch (rcode) {
			    case eop_noop:	case eop_ld:	case eop_lb:
			    case eop_lc:
				jit_ldxi_i(JIT_R0, rbase, rtoff);
				break;
			    default:
				abort();
			}
			if (
#  if __WORDSIZE == 32
			    (lkind == li32) &&
#  endif
			    (rkind & rrel)) {
			    jext = jit_beqi(JIT_R0, t_int);
			    jump = jit_bnei(JIT_R0, t_float);
			    jit_patch_at(jump, fail);
			}
			else
			    rnext = jit_bnei(JIT_R0, t_int);
		    }
		    if (
#  if __WORDSIZE == 32
			(lkind == li32) &&
#  endif
			(rkind & (rf32|rf64|rrel))) {
			switch (rcode) {
			    case eop_ld:	case eop_lb:
			    right_float_ext_dynamic:
				load_freg_reg_type(rbase, rvoff,
						   JIT_F1, JIT_F1, t_float);
				break;
			    case eop_ldt:	case eop_lbt:
			    right_float_ext_static:
				load_freg_reg_type(rbase, rvoff,
						   JIT_F1, JIT_F1, rtype);
				if (rkind & rf32)
				    jit_extr_f_d(JIT_F1, JIT_F1);
				break;
			    case eop_lc:
				if (rcdyn)	goto right_float_ext_dynamic;
				goto right_float_ext_static;
			    default:
				abort();
			}
			jit_extr_d(JIT_F0, JIT_V1);
			if (east_node(ast3)->code == eop_add)
			    jit_addr_d(JIT_F0, JIT_F0, JIT_F1);
			else
			    jit_subr_d(JIT_F0, JIT_F0, JIT_F1);
			store_freg_implicit(true);
			jump = jit_jmpi();
			jit_patch_at(jump, done);
		    }
		    if (jext)
			jit_patch(jext);
		    switch (rcode) {
			case eop_ld:	case eop_lb:
			right_int_dynamic:
			    load_ireg_reg_type(rbase, rvoff,
					       JIT_R0, JIT_R2, t_int);
			    break;
			case eop_ldt:	case eop_lbt:
			right_int_static:
			    load_ireg_reg_type(rbase, rvoff,
					       JIT_R0, JIT_R2, rtype);
			    zero_sign_extend_reg(rtype, JIT_R0, JIT_R2);
			    break;
			case eop_lc:
			    if (rcdyn)	goto right_int_dynamic;
			    goto right_int_static;
			default:
			    abort();
		    }
		    if (rkind & ru64) {
#  if __WORDSIZE == 32
			jump = jit_blti(JIT_R2, 0);
#  else
			jump = jit_blti(JIT_R0, 0);
#  endif
			jit_patch_at(jump, fail);
		    }
		}
#  if __WORDSIZE == 32
		jit_movr(JIT_R1, JIT_V1);
		if (east_node(ast3)->code == eop_add) {
		    jit_addr(JIT_V1, JIT_V1, JIT_R0);
		    jit_ltr_u(JIT_R0, JIT_V1, JIT_R1);
		}
		else {
		    jit_subr(JIT_V1, JIT_V1, JIT_R0);
		    jit_gtr_u(JIT_R0, JIT_V1, JIT_R1);
		}
		jump = jit_boaddr(JIT_R2, JIT_R0);
		jit_patch_at(jump, fail);
		if (east_node(ast3)->code == eop_add)
		    jump = jit_boaddr(JIT_V2, JIT_R2);
		else
		    jump = jit_bosubr(JIT_V2, JIT_R2);
#  else
		if (east_node(ast3)->code == eop_add)
		    jump = jit_boaddr(JIT_V1, JIT_R0);
		else
		    jump = jit_bosubr(JIT_V1, JIT_R0);
#  endif
		jit_patch_at(jump, fail);
		store_ireg_implicit(lcode != eop_noop);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (doflt) {
		if (lnext) {
		    jit_patch(lnext);
		    lnext = null;
		}
		if (rnext) {
		    jit_patch(rnext);
		    rnext = null;
		}
		if (lkind & lrel) {
		    if (lnext == null || rnext != null) {
			switch (lcode) {
			    case eop_noop:	case eop_ld:	case eop_lb:
			    case eop_lc:
				jit_ldxi_i(JIT_R0, lbase, ltoff);
				break;
			    default:
				abort();
			}
		    }
		    lnext = jit_bnei(JIT_R0, t_float);
		}
		switch (lcode) {
		    case eop_noop:
			maybe_reload_freg_implicit();
			break;
		    case eop_ld:	case eop_lb:
		    left_float_dynamic:
			load_freg_reg_type(lbase, lvoff,
					   JIT_F0, JIT_F0, t_float);
			break;
		    case eop_ldt:	case eop_lbt:
		    left_float_static:
			load_freg_reg_type(lbase, lvoff,
					   JIT_F0, JIT_F0, ltype);
			if (lkind & lf32)
			    jit_extr_f_d(JIT_F0, JIT_F0);
			break;
		    case eop_lc:
			if (lcdyn)	goto left_float_dynamic;
			goto left_float_static;
		    default:
			abort();
		}
		/* set if generating code to convert int to float */
		jcvt = null;
		if (same)
		    jit_movr_d(JIT_F1, JIT_F0);
		else {
		    jext = null;
		    if (rkind & (rint|rrel)) {
			switch (rcode) {
			    case eop_noop:	case eop_ld:	case eop_lb:
			    case eop_lc:
				jit_ldxi_i(JIT_R0, rbase, rtoff);
				break;
			    default:
				abort();
			}
#  if __WORDSIZE == 64
			if (rkind & rint) {
			    jext = jit_beqi(JIT_R0, t_float);
			    jump = jit_bnei(JIT_R0, t_int);
			    jit_patch_at(jump, fail);
			}
			else
#  endif
			    rnext = jit_bnei(JIT_R0, t_float);
		    }
		    if (
#  if __WORDSIZE == 32
			(rkind == ri32)
#  else
			(rkind & (ri32|ri64|ru64|rint))
#  endif
			) {
			switch (rcode) {
			    case eop_ld:	case eop_lb:
			    right_int_ext_dynamic:
				load_ireg_reg_type(rbase, rvoff,
						   JIT_R0, JIT_R2, t_int);
				break;
			    case eop_ldt:	case eop_lbt:
			    right_int_ext_static:
				load_ireg_reg_type(rbase, rvoff,
						   JIT_R0, JIT_R2, rtype);
				zero_sign_extend_reg(rtype, JIT_R0, JIT_R2);
				break;
			    case eop_lc:
				if (rcdyn)	goto right_int_ext_dynamic;
				goto right_int_ext_static;
			    default:
				abort();
			}
#  if __WORDSIZE == 64
			if (rkind & ru64) {
			    jump = jit_blti(JIT_R0, 0);
			    jit_patch_at(jump, fail);
			}
#  endif
			jit_extr_d(JIT_F1, JIT_R0);
			jcvt = jit_jmpi();
		    }
		    if (jext)
			jit_patch(jext);
		    switch (rcode) {
			case eop_ld:	case eop_lb:
			right_float_dynamic:
			    load_freg_reg_type(rbase, rvoff,
					       JIT_F1, JIT_F1, t_float);
			    break;
			case eop_ldt:	case eop_lbt:
			right_float_static:
			    load_freg_reg_type(rbase, rvoff,
					       JIT_F1, JIT_F1, rtype);
			    if (rkind & rf32)
				jit_extr_f_d(JIT_F1, JIT_F1);
			    break;
			case eop_lc:
			    if (rcdyn)	goto right_float_dynamic;
			    goto right_float_static;
			default:
			    abort();
		    }
		}
		/* if did convert int to float */
		if (jcvt)
		    jit_patch(jcvt);
		if (east_node(ast3)->code == eop_add)
		    jit_addr_d(JIT_F0, JIT_F0, JIT_F1);
		else
		    jit_subr_d(JIT_F0, JIT_F0, JIT_F1);
		store_freg_implicit(lcode != eop_noop);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	fallback:
	    if (fail)
		jit_link(fail);
	    if (lnext)
		jit_patch(lnext);
	    if (rnext)
		jit_patch(rnext);
	    switch (lcode) {
		case eop_noop:						break;
		case eop_ld:	call_vi(evm_ld, lsoff);			break;
		case eop_ldt:	call_vii(evm_ldt, lsoff, ltype);	break;
		case eop_lb:	call_vi(evm_lb, lsoff);			break;
		case eop_lbt:	call_vii(evm_lbt, lsoff, ltype);	break;
		case eop_lc:	call_vii(evm_lc, lsoff, ltype);		break;
		default:	abort();
	    }
	    jit_calli(evm_push);
	    if (!same) {
		switch (rcode) {
		    case eop_noop:					break;
		    case eop_ld:	call_vi(evm_ld, rsoff);		break;
		    case eop_ldt:	call_vii(evm_ldt, rsoff, rtype);break;
		    case eop_lb:	call_vi(evm_lb, rsoff);		break;
		    case eop_lbt:	call_vii(evm_lbt, rsoff, rtype);break;
		    case eop_lc:	call_vii(evm_lc, rsoff, rtype);	break;
		    default:	abort();
		}
	    }
	    if (east_node(ast3)->code == eop_add)
		jit_calli(evm_add);
	    else
		jit_calli(evm_sub);
	    next = jump = null;
	    if (ikind & (iint|if64|irel))
		jit_ldxi_i(JIT_R0, JIT_V0,
			   offsetof(ethread_t, r0) + offsetof(evalue_t, t));
	    if (ikind & iint) {
		next = jit_bnei(JIT_R0, t_int);
		load_ireg_implicit();
		jump = jit_jmpi();
	    }
	    else
		DEBUG_IMPLICIT_TYPE_INT();
	    if (ikind & (if64|irel)) {
		if (next)
		    jit_patch(next);
		next = jit_bnei(JIT_R0, t_float);
		load_freg_implicit();
	    }
	    else
		DEBUG_IMPLICIT_TYPE_FLOAT();
	    if (jump)
		jit_patch(jump);
	    if (next)
		jit_patch(next);
	    if (done)
		jit_link(done);
	    ejit_sync = ejit_sync_register|ejit_sync_implicit|
			ejit_sync_dynamic|ejit_sync_int_ext;
	    break;
    }
    ejit_type = ast3->itype;
}

static void
emit_lr(east_list_t *ast0)
{
    jit_node_t		*jump;
    eint32_t		 base;
    eint32_t		 kind;
    esymbol_t		*symbol;

    symbol = east_node(ast0)->crecord.symbol;
    base = east_node(ast0)->crecord.record->type;
    switch (ast0->itype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:	case t_uint32:	case t_int:	case t_uint:
	    kind = iint;		break;
	case t_float32:	case t_float:
	    kind = irel;		break;
	default:
	    kind = 0;			break;
    }
    if (kind) {
	assert(east_node(ast0)->crecord.symbol->type == ast0->itype);
	jit_ldxi_i(JIT_R0, JIT_V0,
		   offsetof(ethread_t, r0) + offsetof(evalue_t, t));
	jump = jit_beqi(JIT_R0, base);
	jit_prepare(jit_call_default);
	jit_pushargi(base);
	jit_pushargr(JIT_R0);
	jit_pushargi(symbol->offset);
	jit_finishi(evm_match_inheritance);
	jit_patch(jump);
	jit_ldxi(JIT_R1, JIT_V0,
		 offsetof(ethread_t, r0) + offsetof(evalue_t, v.o));
	if (kind & iint)
	    load_ireg_type(JIT_R1, symbol->offset, ast0->itype);
	else
	    load_freg_type(JIT_R1, symbol->offset, ast0->itype);
	ejit_sync = ejit_sync_register;
    }
    else {
	emit_clear();
	call_viii(evm_lr, base, symbol->offset, ast0->itype);
	ejit_sync = ejit_sync_dynamic|ejit_sync_implicit;
    }
     ejit_type = ast0->itype;
}

static void
emit_store_stack(east_list_t *ast0, eint32_t offset)
{
    jit_node_t		*done;
    jit_node_t		*jump;
    jit_node_t		*next;
    jit_node_t		*over;
    eint32_t		 kind;

    switch (ast0->rtype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:	case t_uint32:
	    kind = ii32;		break;
	case t_int:
	    kind = ii64;		break;
	case t_uint:
	    kind = iu64;		break;
	case t_float32:
	    kind = if32;		break;
	case t_float:
	    kind = if64;		break;
	case t_exact:
	    kind = iint;		break;
	case t_inexact:
	    kind = irel;		break;
	case t_dynamic:
	    kind = iint|irel;		break;
	default:
	    kind = 0;			break;
    }
    switch (kind) {
	case ii32:
	    maybe_reload_extend_ireg_implicit(ast0->itype);
	    store_ireg_value_type(JIT_R1, offset);
	    break;
	case ii64:
	    maybe_reload_ireg_implicit();
	    store_ireg_value_type(JIT_R1, offset);
	    break;
	case iu64:
	    next = null;
	    if (!(ejit_sync & ejit_sync_register)) {
		assert(ejit_sync & ejit_sync_implicit);
		jit_ldxi_i(JIT_R0, JIT_V0,
			   offsetof(ethread_t, r0) + offsetof(evalue_t, t));
		next = jit_bnei(JIT_R0, t_int);
		load_ireg_implicit();
	    }
#  if __WORDSIZE == 32
	    over = jit_blti(JIT_V2, 0);
#  else
	    over = jit_blti(JIT_V1, 0);
#  endif
	    if (!(ejit_sync & ejit_sync_implicit))
		store_ireg_implicit(true);
	    store_ireg_value_type(JIT_R1, offset);
	    done = jit_forward();
	    jump = jit_jmpi();
	    jit_patch_at(jump, done);
	    jit_patch(over);
#  if __WORDSIZE == 32
	    store_ireg_implicit_rgz(RGZ_r1_to_v1, JIT_V1, JIT_V2);
#  else
	    store_ireg_implicit_rgz(RGZ_r1_to_v1, JIT_V1);
#  endif
	    /* multiple paths */
	    jit_movr(JIT_R1, JIT_V1);
	    goto overflow;
	case if32:
	    if (!(ejit_sync & ejit_sync_register))
		load_freg_implicit();
	    else if (!(ejit_sync & ejit_sync_float_ext)) {
		jit_extr_f_d(JIT_F0, JIT_F1);
		ejit_sync |= ejit_sync_float_ext;
	    }
	    store_freg_value_type(JIT_R1, offset);
	    break;
	case if64:
	    maybe_reload_freg_implicit();
	    store_freg_value_type(JIT_R1, offset);
	    break;
	default:
	    assert(ejit_sync & ejit_sync_implicit);
	    ejit_sync |= ejit_sync_dynamic;
	    done = next = null;
	    if (kind) {
		done = jit_forward();
		jit_ldxi_i(JIT_R0, JIT_V0,
			   offsetof(ethread_t, r0) + offsetof(evalue_t, t));
	    }
	    if (kind & iint) {
		next = jit_bnei(JIT_R0, t_int);
		maybe_reload_ireg_implicit();
		store_ireg_value_type(JIT_R1, offset);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (kind & irel) {
		if (next)
		    jit_patch(next);
		next = jit_bnei(JIT_R0, t_float);
		maybe_reload_freg_implicit();
		store_freg_value_type(JIT_R1, offset);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	overflow:
	    if (next)
		jit_patch(next);
	    jit_prepare(jit_call_default);
	    if (offset)
		jit_addi(JIT_R1, JIT_R1, offset);
	    jit_pushargr(JIT_R1);
	    switch (east_node(ast0)->code) {
		case eop_sb:		case eop_ssv:
		    jit_finishi(evm_store_value);
		    break;
		case eop_push:		case eop_ss:
		    jit_finishi(evm_store_value_push);
		    break;
		case eop_pushv:
		    jit_finishi(evm_store_value_copy);
		    break;
		default:
		    abort();
	    }
	    DEBUG_IMPLICIT_TYPE();
	    if (done)
		jit_link(done);
	    ejit_sync = ejit_sync_dynamic|ejit_sync_implicit;
	    break;
    }
    ejit_sync |= ejit_sync_register;
    ejit_type = ast0->itype;
}

static void
emit_store_type(east_list_t *ast0, eint32_t offset, eint32_t type)
{
    jit_node_t		*done;
    jit_node_t		*jump;
    jit_node_t		*next;
    eint32_t		 kind;

    switch (ast0->itype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:	case t_uint32:
	    kind = ii32;		break;
	case t_int:
	    kind = ii64;		break;
	case t_uint:
	    kind = iu64;		break;
	case t_float32:
	    kind = if32;		break;
	case t_float:
	    kind = if64;		break;
	case t_exact:
	    kind = iint;		break;
	case t_inexact:
	    kind = irel;		break;
	case t_dynamic:
	    kind = iint|irel;		break;
	default:
	    kind = 0;			break;
    }
    switch (kind) {
	case ii32:
	    maybe_reload_ireg_implicit();
	    store_int32(JIT_R1, offset, type);
	    break;
	case ii64:
	    maybe_reload_ireg_implicit();
	    store_int(JIT_R1, offset, type);
	    break;
	case iu64:
	    jump = null;
	    if (!(ejit_sync & ejit_sync_register)) {
		assert(ejit_sync & ejit_sync_implicit);
		jit_ldxi_i(JIT_R0, JIT_V0,
			   offsetof(ethread_t, r0) + offsetof(evalue_t, t));
		jump = jit_bnei(JIT_R0, t_int);
		load_ireg_implicit();
		ejit_sync |= ejit_sync_register|ejit_sync_int_ext;
	    }
	    store_int(JIT_R1, offset, type);
	    if (jump) {
		done = jit_jmpi();
		jit_patch(jump);
		store_dynamic(JIT_R1, offset, type);
		jit_patch(done);
	    }
	    break;
	case if32:
	    maybe_reload_freg_implicit();
	    store_float32(JIT_R1, offset, type);
	    break;
	case if64:
	    maybe_reload_freg_implicit();
	    store_float(JIT_R1, offset, type);
	    break;
	default:
	    assert(ejit_sync & ejit_sync_implicit);
	    ejit_sync |= ejit_sync_dynamic;
	    next = done = null;
	    if (kind) {
		done = jit_forward();
		jit_ldxi_i(JIT_R0, JIT_V0,
			   offsetof(ethread_t, r0) + offsetof(evalue_t, t));
	    }
	    if (kind & iint) {
		next = jit_bnei(JIT_R0, t_int);
		maybe_reload_ireg_implicit();
		store_int(JIT_R1, offset, type);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (kind & irel) {
		if (next)
		    jit_patch(next);
		next = jit_bnei(JIT_R0, t_float);
		maybe_reload_freg_implicit();
		store_float(JIT_R1, offset, type);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (next)
		jit_patch(next);
	    store_dynamic(JIT_R1, offset, type);
	    DEBUG_IMPLICIT_TYPE();
	    if (done)
		jit_link(done);
	    ejit_sync = ejit_sync_register|ejit_sync_dynamic|ejit_sync_implicit;
	    break;
    }
    ejit_type = ast0->itype;
}

static void
emit_sdt(east_list_t *ast0)
{
    jit_ldi(JIT_R1,
	    (jit_word_t)((eint8_t *)eds +
			 east_node(ast0)->csymbol.symbol->offset *
			 sizeof(eobject_t)));
    emit_store_type(ast0, 0, east_node(ast0)->csymbol.symbol->type);
}

static void
emit_sb(east_list_t *ast0)
{
    jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
    emit_store_stack(ast0, east_node(ast0)->csymbol.symbol->offset *
		     sizeof(evalue_t));
}

static void
emit_sbt(east_list_t *ast0)
{
    jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
    emit_store_type(ast0,
		    east_node(ast0)->csymbol.symbol->offset * sizeof(evalue_t) +
		    offsetof(evalue_t, v.o),
		    east_node(ast0)->csymbol.symbol->type);
}

static void
emit_sr(east_list_t *ast0)
{
    jit_node_t		*jump;
    eint32_t		 base;
    ebool_t		 reload;
    esymbol_t		*symbol;

    symbol = east_node(ast0)->crecord.symbol;
    base = east_node(ast0)->crecord.record->type;
    if (symbol->type == t_void || symbol->type > elast_basic_type) {
	emit_sync();
	call_viii(evm_sr, base, symbol->offset, symbol->type);
    }
    else {
	/* FIXME should generate proper intermediate representation
	 * to only call evm_match_inheritance when really needed,
	 * and if applicable, move it out of loops */
	reload = (ejit_type == t_float32 || ejit_type == t_float) &&
		!(ejit_sync & ejit_sync_implicit);
	if (reload) {
	    assert(ejit_sync & ejit_sync_register);
	    if (ejit_type == t_float32 &&
		!(ejit_sync & ejit_sync_float_ext)) {
		jit_extr_f_d(JIT_F0, JIT_F1);
		ejit_sync |= ejit_sync_float_ext;
	    }
	    store_freg_implicit(true);
	    ejit_sync |= ejit_sync_implicit;
	}
	jit_ldxi(JIT_R0, JIT_V0, offsetof(ethread_t, esp));
	jit_ldxi_i(JIT_R0, JIT_R0,
		   -sizeof(evalue_t) + offsetof(evalue_t, t));
	jump = jit_beqi(JIT_R0, base);
	jit_prepare(jit_call_default);
	jit_pushargi(base);
	jit_pushargr(JIT_R0);
	jit_pushargi(symbol->offset);
	jit_finishi(evm_match_inheritance);
	if (reload) {
	    load_freg_implicit();
	    if (ejit_type == t_float32) {
		jit_extr_d_f(JIT_F1, JIT_F0);
		ejit_sync |= ejit_sync_float_ext;
	    }
	}
	jit_patch(jump);
	jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, esp));
	jit_ldxi(JIT_R1, JIT_R1,
		 -sizeof(evalue_t) + offsetof(evalue_t, v.o));
	emit_store_type(ast0, symbol->offset, symbol->type);
	jit_ldxi(JIT_R0, JIT_V0, offsetof(ethread_t, esp));
	jit_subi(JIT_R0, JIT_R0, sizeof(evalue_t));
	jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_R0);
    }
    ejit_type = ast0->itype;
}

static void
emit_sc(east_list_t *ast0)
{
    eint32_t		type;

    type = east_node(ast0)->csymbol.symbol->type;
    if (type == t_void || type > elast_basic_type) {
	emit_sync();
	call_vii(evm_sc, east_node(ast0)->csymbol.symbol->offset, type);
    }
    else {
	jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
	jit_ldxi(JIT_R1, JIT_R1,
		 -2 * sizeof(evalue_t) + offsetof(evalue_t, v.o));
	emit_store_type(ast0, east_node(ast0)->csymbol.symbol->offset, type);
    }
    ejit_type = ast0->itype;
}

static void
emit_ss(east_list_t *ast0)
{
    jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, esp));
    emit_store_stack(ast0, east_node(ast0)->cstack.offset * sizeof(evalue_t));
}

static void
emit_sst(east_list_t *ast0)
{
    jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, esp));
    jit_movi(JIT_R0, east_node(ast0)->cstack.type);
    jit_stxi_i(sizeof(evalue_t) * east_node(ast0)->cstack.offset +
	       offsetof(evalue_t, t),
	       JIT_R1, JIT_R0);
    emit_store_type(ast0, east_node(ast0)->cstack.offset * sizeof(evalue_t) +
		    offsetof(evalue_t, v.o), east_node(ast0)->cstack.type);
}

static void
emit_push(east_list_t *ast0)
{
    jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, esp));
    jit_addi(JIT_R0, JIT_R1, sizeof(evalue_t));
    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_R0);
    emit_store_stack(ast0, 0);
}

static void
emit_pusht(east_list_t *ast0)
{
    jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, esp));
    jit_addi(JIT_R0, JIT_R1, sizeof(evalue_t));
    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_R0);
    jit_movi(JIT_R0, east_node(ast0)->cstack.type);
    jit_stxi_i(offsetof(evalue_t, t), JIT_R1, JIT_R0);
    emit_store_type(ast0, offsetof(evalue_t, v.o),
		    east_node(ast0)->cstack.type);
}

static void
emit_cmp(east_list_t *ast0)
{
    jit_node_t		*done;
    jit_node_t		*jump;
    jit_node_t		*jint;
    jit_node_t		*jflt;
    jit_node_t		*jmpz;
    jit_node_t		*load;
    jit_node_t		*next;
    jit_node_t		*temp;
    eint32_t		 kind;

    jmpz = null;
    switch (ast0->ltype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    kind = li32;		break;
	case t_uint32:	case t_int:
	    kind = li64;		break;
	case t_float:
	    kind = lf64;		break;
	case t_exact:
	    kind = lint;		break;
	case t_inexact:
	    kind = irel;		break;
	case t_dynamic:
	    kind = lint|lrel;		break;
	default:
	    kind = 0;			break;
    }
    switch (ast0->rtype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    kind |= ri32;		break;
	case t_uint32:	case t_int:
	    kind |= ri64;		break;
	case t_uint:
	    kind |= ru64;		break;
	case t_float32:
	    kind |= rf32;		break;
	case t_float:
	    kind |= rf64;		break;
	case t_exact:
	    kind |= rint;		break;
	case t_inexact:
	    kind |= rrel;		break;
	case t_dynamic:
	    kind |= rint|rrel;		break;
	default:			break;
    }
    switch (kind) {
	case li32|ri32:
	    load_stack();
	    maybe_reload_ireg32_implicit();
	    jit_ldxi_i(JIT_R0, JIT_R1,
		       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		       offsetof(edata_t, s.l));
	    switch (east_node(ast0)->code) {
		case eop_lt:	jit_ger(JIT_V1, JIT_V1, JIT_R0);	break;
		case eop_le:	jit_gtr(JIT_V1, JIT_V1, JIT_R0);	break;
		case eop_eq:	jit_eqr(JIT_V1, JIT_V1, JIT_R0);	break;
		case eop_ge:	jit_ltr(JIT_V1, JIT_V1, JIT_R0);	break;
		case eop_gt:	jit_ler(JIT_V1, JIT_V1, JIT_R0);	break;
		default:	jit_ner(JIT_V1, JIT_V1, JIT_R0);	break;
	    }
	    pop_stack();
	    ejit_sync = ejit_sync_register;
	    break;
	case li32|ri64:		case li64|ri32:		case li64|ri64:
	case li32|ru64:		case li64|ru64:
	    load_stack();
	    maybe_reload_extend_ireg_implicit(ast0->rtype);
	    if (kind & ru64) {
#  if __WORDSIZE == 32
		next = jit_bgei(JIT_V2, 0);
		store_ireg_implicit_rgz(RGZ_r1_pop_to_v1, JIT_V1, JIT_V2);
#  else
		next = jit_bgei(JIT_V1, 0);
		store_ireg_implicit_rgz(RGZ_r1_pop_to_v1, JIT_V1);
#  endif
		jit_prepare(jit_call_default);
		jit_pushargr(JIT_V1);
		switch (east_node(ast0)->code) {
		    case eop_ne:	jit_finishi(evm_z_ne);		break;
		    case eop_lt:	jit_finishi(evm_z_lt);		break;
		    case eop_le:	jit_finishi(evm_z_le);		break;
		    case eop_eq:	jit_finishi(evm_z_eq);		break;
		    case eop_ge:	jit_finishi(evm_z_ge);		break;
		    default:		jit_finishi(evm_z_gt);		break;
		}
		jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
		load_ireg32_implicit();
		jmpz = jit_jmpi();
		jit_patch(next);
	    }
#  if __WORDSIZE == 32
	    jit_ldxi_i(JIT_R0, JIT_R1,
		       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		       offsetof(edata_t, s.l));
	    jit_ldxi_i(JIT_R2, JIT_R1,
		       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		       offsetof(edata_t, s.h));
	    switch (east_node(ast0)->code) {
		case eop_lt:
		    jump = jit_bner(JIT_V2, JIT_R2);
		    jit_ltr_u(JIT_V1, JIT_R0, JIT_V1);
		    temp = jit_jmpi();
		    jit_patch(jump);
		    jit_ltr(JIT_V1, JIT_R2, JIT_V2);
		    jit_patch(temp);
		    break;
		case eop_le:
		    jump = jit_bner(JIT_V2, JIT_R2);
		    jit_ler_u(JIT_V1, JIT_R0, JIT_V1);
		    temp = jit_jmpi();
		    jit_patch(jump);
		    jit_ltr(JIT_V1, JIT_R2, JIT_V2);
		    jit_patch(temp);
		    break;
		case eop_eq:
		    jit_eqr(JIT_V1, JIT_V1, JIT_R0);
		    jit_eqr(JIT_V2, JIT_V2, JIT_R2);
		    jit_andr(JIT_V1, JIT_V1, JIT_V2);
		    break;
		case eop_ge:
		    jump = jit_bner(JIT_V2, JIT_R2);
		    jit_ger_u(JIT_V1, JIT_R0, JIT_V1);
		    temp = jit_jmpi();
		    jit_patch(jump);
		    jit_gtr(JIT_V1, JIT_R2, JIT_V2);
		    jit_patch(temp);
		    break;
		case eop_gt:
		    jump = jit_bner(JIT_V2, JIT_R2);
		    jit_gtr_u(JIT_V1, JIT_R0, JIT_V1);
		    temp = jit_jmpi();
		    jit_patch(jump);
		    jit_gtr(JIT_V1, JIT_R2, JIT_V2);
		    jit_patch(temp);
		    break;
		default:
		    jit_ner(JIT_V1, JIT_V1, JIT_R0);
		    jit_ner(JIT_V2, JIT_V2, JIT_R2);
		    jit_orr(JIT_V1, JIT_V1, JIT_V2);
		    break;
	    }
#  else
	    jit_ldxi_i(JIT_R0, JIT_R1,
		       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		       offsetof(edata_t, s.l));
	    switch (east_node(ast0)->code) {
		case eop_lt:	jit_ger(JIT_V1, JIT_V1, JIT_R0);	break;
		case eop_le:	jit_gtr(JIT_V1, JIT_V1, JIT_R0);	break;
		case eop_eq:	jit_eqr(JIT_V1, JIT_V1, JIT_R0);	break;
		case eop_ge:	jit_ltr(JIT_V1, JIT_V1, JIT_R0);	break;
		case eop_gt:	jit_ler(JIT_V1, JIT_V1, JIT_R0);	break;
		default:	jit_ner(JIT_V1, JIT_V1, JIT_R0);	break;
	    }
#  endif
	    if (jmpz)
		jit_patch(jmpz);
	    ejit_sync = ejit_sync_register;
	    break;
	case li32|rf32:		case li32|rf64:
	    load_stack();
	    if (kind & rf32) {
		if (!(ejit_sync & ejit_sync_register))
		    load_freg_implicit();
		else if (!(ejit_sync & ejit_sync_float_ext))
		    jit_extr_f_d(JIT_F0, JIT_F1);
	    }
	    else
		maybe_reload_freg_implicit();
	    jit_ldxi_i(JIT_R0, JIT_R1,
		       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		       offsetof(edata_t, s.l));
	    jit_extr_d(JIT_F2, JIT_R0);
	    goto float_float;
	case li64|rf32:		case li64|rf64:
	    load_stack();
#  if __WORDSIZE == 32
	    if (!(ejit_sync & ejit_sync_implicit)) {
		assert(ejit_sync & ejit_sync_register);
		if ((kind & rf32) && !(ejit_sync & ejit_sync_float_ext))
		    jit_extr_f_d(JIT_F0, JIT_F1);
		store_freg_implicit(true);
	    }
	    jit_prepare(jit_call_default);
	    jit_subi(JIT_V2, JIT_R1, sizeof(evalue_t));
	    jit_pushargr(JIT_V2);
	    switch (east_node(ast0)->code) {
		case eop_ne:		jit_finishi(evm_d_ne);		break;
		case eop_lt:		jit_finishi(evm_d_lt);		break;
		case eop_le:		jit_finishi(evm_d_le);		break;
		case eop_eq:		jit_finishi(evm_d_eq);		break;
		case eop_ge:		jit_finishi(evm_d_ge);		break;
		default:		jit_finishi(evm_d_gt);		break;
	    }
	    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V2);
	    load_ireg32_implicit();
	    ejit_sync = ejit_sync_register|ejit_sync_implicit;
	    break;
#  else
	    if (kind & rf32) {
		if (!(ejit_sync & ejit_sync_register))
		    load_freg_implicit();
		else if (!(ejit_sync & ejit_sync_float_ext))
		    jit_extr_f_d(JIT_F0, JIT_F1);
	    }
	    else
		maybe_reload_freg_implicit();
	    jit_ldxi(JIT_R0, JIT_R1,
		     -sizeof(evalue_t) + offsetof(evalue_t, v.i));
	    jit_extr_d(JIT_F2, JIT_R0);
	    goto float_float;
#  endif
	case lf64|ri32:
	    load_stack();
	    maybe_reload_ireg32_implicit();
	    jit_extr_d(JIT_F0, JIT_V1);
	    goto load_float_float;
	case lf64|ri64:		case lf64|ru64:
	    load_stack();
	    maybe_reload_extend_ireg_implicit(ast0->rtype);
	    if (kind & ru64) {
#  if __WORDSIZE == 32
		next = jit_bgei(JIT_V2, 0);
		store_ireg_implicit_rgz(RGZ_r1_pop_to_v1, JIT_V1, JIT_V2);
#  else
		next = jit_bgei(JIT_V1, 0);
		store_ireg_implicit_rgz(RGZ_r1_pop_to_v1, JIT_V1);
#  endif
		jit_prepare(jit_call_default);
		jit_pushargr(JIT_V1);
		switch (east_node(ast0)->code) {
		    case eop_ne:	jit_finishi(evm_z_ne);		break;
		    case eop_lt:	jit_finishi(evm_z_lt);		break;
		    case eop_le:	jit_finishi(evm_z_le);		break;
		    case eop_eq:	jit_finishi(evm_z_eq);		break;
		    case eop_ge:	jit_finishi(evm_z_ge);		break;
		    default:		jit_finishi(evm_z_gt);		break;
		}
		jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
		load_ireg32_implicit();
		jmpz = jit_jmpi();
		jit_patch(next);
	    }
#  if __WORDSIZE == 32
	    if (!(ejit_sync & ejit_sync_implicit))
		store_ireg_implicit(true);
	    jit_addi(JIT_R0, JIT_V0, offsetof(ethread_t, r0) +
		     offsetof(evalue_t, v.d));
	    jit_prepare(jit_call_default);
	    jit_pushargr(JIT_R0);
	    jit_finishi(evm_store_float64);
	    load_freg_implicit();
#  else
	    jit_extr_d(JIT_F0, JIT_V1);
#  endif
	    goto load_float_float;
	case lf64|rf32:
	    load_stack();
	    if (!(ejit_sync & ejit_sync_register))
		load_freg_implicit();
	    else if (!(ejit_sync & ejit_sync_float_ext))
		jit_extr_f_d(JIT_F0, JIT_F1);
	    goto load_float_float;
	case lf64|rf64:
	    load_stack();
	    maybe_reload_freg_implicit();
	load_float_float:
	    jit_ldxi_d(JIT_F2, JIT_R1,
		       -sizeof(evalue_t) + offsetof(evalue_t, v.d));
	float_float:
	    switch (east_node(ast0)->code) {
		case eop_ne:	jit_ner_d(JIT_V1, JIT_F2, JIT_F0);	break;
		case eop_lt:	jit_ltr_d(JIT_V1, JIT_F2, JIT_F0);	break;
		case eop_le:	jit_ler_d(JIT_V1, JIT_F2, JIT_F0);	break;
		case eop_eq:	jit_eqr_d(JIT_V1, JIT_F2, JIT_F0);	break;
		case eop_ge:	jit_ger_d(JIT_V1, JIT_F2, JIT_F0);	break;
		default:	jit_gtr_d(JIT_V1, JIT_F2, JIT_F0);	break;
	    }
	    pop_stack();
	    if (jmpz)
		jit_patch(jmpz);
	    ejit_sync = ejit_sync_register;
	    break;
	default:
	    jint = jflt = next = null;
	    if (kind & (ri32|ri64|ru64|rint|rf32|rf64|rrel)) {
		load_stack();
		done = jit_forward();
		load = jit_forward();
		if (kind & (rint|rrel))
		    jit_ldxi_i(JIT_R0, JIT_V0,
			       offsetof(ethread_t, r0) + offsetof(evalue_t, t));
	    }
	    else
		done = load = null;
	    if (kind & (ri32|ri64|ru64|rint)) {
		if (!(kind & (ri32|ri64|ru64)))
		    next = jit_bnei(JIT_R0, t_int);
		if (!(ejit_sync & ejit_sync_register))
		    load_ireg_implicit();
		else if ((kind & ri32) && !(ejit_sync & ejit_sync_int_ext))
		    zero_sign_extend(ast0->rtype);
		if (kind & ru64) {
		    jmpz = jit_forward();
#  if __WORDSIZE == 32
		    jump = jit_blti(JIT_V2, 0);
#  else
		    jump = jit_blti(JIT_V1, 0);
#  endif
		    jit_patch_at(jump, jmpz);
		}
		if (!(kind & (li32|li64))) {
		    jint = jit_forward();
		    jit_ldxi_i(JIT_R0, JIT_R1,
			       -sizeof(evalue_t) + offsetof(evalue_t, t));
		    if (
#  if __WORDSIZE == 32
			(kind & li32)
#  else
			(kind & (li32|li64|lint))
#  endif
			) {
			temp = jit_beqi(JIT_R0, t_int);
			jump = jit_bnei(JIT_R0, t_float);
			jit_patch_at(jump, jint);
			jit_extr_d(JIT_F0, JIT_V1);
			jit_ldxi_d(JIT_F2, JIT_R1,
				   -sizeof(evalue_t) + offsetof(evalue_t, v.d));
			switch (east_node(ast0)->code) {
			    case eop_ne:jit_ner_d(JIT_V1, JIT_F2, JIT_F0);break;
			    case eop_lt:jit_ltr_d(JIT_V1, JIT_F2, JIT_F0);break;
			    case eop_le:jit_ler_d(JIT_V1, JIT_F2, JIT_F0);break;
			    case eop_eq:jit_eqr_d(JIT_V1, JIT_F2, JIT_F0);break;
			    case eop_ge:jit_ger_d(JIT_V1, JIT_F2, JIT_F0);break;
			    default:	jit_gtr_d(JIT_V1, JIT_F2, JIT_F0);break;
			}
#  if __WORDSIZE == 32
			jit_movi(JIT_V2, 0);
#  endif
			store_ireg_implicit(!(ejit_sync & ejit_sync_implicit));
			jump = jit_jmpi();
			jit_patch_at(jump, done);
			jit_patch(temp);
		    }
		    else {
			jump = jit_bnei(JIT_R0, t_int);
			jit_patch_at(jump, jint);
		    }
		}
#  if __WORDSIZE == 32
		jit_ldxi_i(JIT_R0, JIT_R1,
			   -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
			   offsetof(edata_t, s.l));
		jit_ldxi_i(JIT_R2, JIT_R1,
			   -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
			   offsetof(edata_t, s.h));
		switch (east_node(ast0)->code) {
		    case eop_lt:
			jump = jit_bner(JIT_V2, JIT_R2);
			jit_ltr_u(JIT_V1, JIT_R0, JIT_V1);
			temp = jit_jmpi();
			jit_patch(jump);
			jit_ltr(JIT_V1, JIT_R2, JIT_V2);
			jit_patch(temp);
			break;
		    case eop_le:
			jump = jit_bner(JIT_V2, JIT_R2);
			jit_ler_u(JIT_V1, JIT_R0, JIT_V1);
			temp = jit_jmpi();
			jit_patch(jump);
			jit_ltr(JIT_V1, JIT_R2, JIT_V2);
			jit_patch(temp);
			break;
		    case eop_eq:
			jit_eqr(JIT_V1, JIT_V1, JIT_R0);
			jit_eqr(JIT_V2, JIT_V2, JIT_R2);
			jit_andr(JIT_V1, JIT_V1, JIT_V2);
			break;
		    case eop_ge:
			jump = jit_bner(JIT_V2, JIT_R2);
			jit_ger_u(JIT_V1, JIT_R0, JIT_V1);
			temp = jit_jmpi();
			jit_patch(jump);
			jit_gtr(JIT_V1, JIT_R2, JIT_V2);
			jit_patch(temp);
			break;
		    case eop_gt:
			jump = jit_bner(JIT_V2, JIT_R2);
			jit_gtr_u(JIT_V1, JIT_R0, JIT_V1);
			temp = jit_jmpi();
			jit_patch(jump);
			jit_gtr(JIT_V1, JIT_R2, JIT_V2);
			jit_patch(temp);
			break;
		    default:
			jit_ner(JIT_V1, JIT_V1, JIT_R0);
			jit_ner(JIT_V2, JIT_V2, JIT_R2);
			jit_orr(JIT_V1, JIT_V1, JIT_V2);
			break;
		}
		jit_movi(JIT_V2, 0);
#  else
		jit_ldxi_i(JIT_R0, JIT_R1,
			   -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
			   offsetof(edata_t, s.l));
		switch (east_node(ast0)->code) {
		    case eop_lt:jit_ger(JIT_V1, JIT_V1, JIT_R0);	break;
		    case eop_le:jit_gtr(JIT_V1, JIT_V1, JIT_R0);	break;
		    case eop_eq:jit_eqr(JIT_V1, JIT_V1, JIT_R0);	break;
		    case eop_ge:jit_ltr(JIT_V1, JIT_V1, JIT_R0);	break;
		    case eop_gt:jit_ler(JIT_V1, JIT_V1, JIT_R0);	break;
		    default:	jit_ner(JIT_V1, JIT_V1, JIT_R0);	break;
		}
#  endif
		pop_stack();
		store_ireg_implicit(!(ejit_sync & ejit_sync_implicit));
		jump = jit_jmpi();
		jit_patch_at(jump, done);
		if (jint) {
		    jit_link(jint);
		    if (!(ejit_sync & ejit_sync_implicit))
			store_ireg_implicit(true);
		    jit_prepare(jit_call_default);
		    jit_subi(JIT_V2, JIT_R1, sizeof(evalue_t));
		    jit_pushargr(JIT_V2);
		    switch (east_node(ast0)->code) {
			case eop_ne:	jit_finishi(evm_i_ne);		break;
			case eop_lt:	jit_finishi(evm_i_lt);		break;
			case eop_le:	jit_finishi(evm_i_le);		break;
			case eop_eq:	jit_finishi(evm_i_eq);		break;
			case eop_ge:	jit_finishi(evm_i_ge);		break;
			default:	jit_finishi(evm_i_gt);		break;
		    }
		    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V2);
		    jump = jit_jmpi();
		    jit_patch_at(jump, load);
		}
		if (jmpz) {
		    jit_link(jmpz);
#  if __WORDSIZE == 32
		    store_ireg_implicit_rgz(RGZ_r1_pop_to_v1, JIT_V1, JIT_V2);
#  else
		    store_ireg_implicit_rgz(RGZ_r1_pop_to_v1, JIT_V1);
#  endif
		    jit_prepare(jit_call_default);
		    jit_pushargr(JIT_V1);
		    switch (east_node(ast0)->code) {
			case eop_ne:	jit_finishi(evm_z_ne);		break;
			case eop_lt:	jit_finishi(evm_z_lt);		break;
			case eop_le:	jit_finishi(evm_z_le);		break;
			case eop_eq:	jit_finishi(evm_z_eq);		break;
			case eop_ge:	jit_finishi(evm_z_ge);		break;
			default:	jit_finishi(evm_z_gt);		break;
		    }
		    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
		    jump = jit_jmpi();
		    jit_patch_at(jump, load);
		}
	    }
	    if (kind & (rf32|rf64|rrel)) {
		jump = null;
		if (next)
		    jit_patch(next);
		if (!(kind & (rf32|rf64)))
		    next = jit_bnei(JIT_R0, t_float);
		if (!(ejit_sync & ejit_sync_register))
		    load_freg_implicit();
		else if ((kind & rf32) && !(ejit_sync & ejit_sync_float_ext))
		    jit_extr_f_d(JIT_F0, JIT_F1);
		if (!(kind & lf64)) {
		    jflt = jit_forward();
		    jit_ldxi_i(JIT_R0, JIT_R1,
			       -sizeof(evalue_t) + offsetof(evalue_t, t));
		    if (
#  if __WORDSIZE == 32
			(kind & li32)
#  else
			(kind & (li32|li64|lint))
#  endif
			) {
			temp = jit_beqi(JIT_R0, t_float);
			jump = jit_bnei(JIT_R0, t_int);
			jit_patch_at(jump, jflt);
#  if __WORDSIZE == 32
			jit_ldxi_i(JIT_R2, JIT_R1,
				   -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
				   offsetof(edata_t, s.l));
#  else
			jit_ldxi(JIT_R2, JIT_R1,
				 -sizeof(evalue_t) + offsetof(evalue_t, v.i));
#  endif
			jit_extr_d(JIT_F2, JIT_R2);
			jump = jit_jmpi();
			jit_patch(temp);
		    }
		    else {
			temp = jit_bnei(JIT_R0, t_float);
			jit_patch_at(temp, jflt);
		    }
		}
		jit_ldxi_d(JIT_F2, JIT_R1,
			   -sizeof(evalue_t) + offsetof(evalue_t, v.d));
		if (jump)
		    jit_patch(jump);
		switch (east_node(ast0)->code) {
		    case eop_ne:jit_ner_d(JIT_V1, JIT_F2, JIT_F0);	break;
		    case eop_lt:jit_ltr_d(JIT_V1, JIT_F2, JIT_F0);	break;
		    case eop_le:jit_ler_d(JIT_V1, JIT_F2, JIT_F0);	break;
		    case eop_eq:jit_eqr_d(JIT_V1, JIT_F2, JIT_F0);	break;
		    case eop_ge:jit_ger_d(JIT_V1, JIT_F2, JIT_F0);	break;
		    default:	jit_gtr_d(JIT_V1, JIT_F2, JIT_F0);	break;
		}
#  if __WORDSIZE == 32
		jit_movi(JIT_V2, 0);
#  endif
		pop_stack();
		store_ireg_implicit(true);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
		if (jflt) {
		    jit_link(jflt);
		    if (!(ejit_sync & ejit_sync_implicit))
			store_freg_implicit(true);
		    jit_prepare(jit_call_default);
		    jit_subi(JIT_V2, JIT_R1, sizeof(evalue_t));
		    jit_pushargr(JIT_V2);
		    switch (east_node(ast0)->code) {
			case eop_ne:	jit_finishi(evm_d_ne);		break;
			case eop_lt:	jit_finishi(evm_d_lt);		break;
			case eop_le:	jit_finishi(evm_d_le);		break;
			case eop_eq:	jit_finishi(evm_d_eq);		break;
			case eop_ge:	jit_finishi(evm_d_ge);		break;
			default:	jit_finishi(evm_d_gt);		break;
		    }
		    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V2);
		    jump = jit_jmpi();
		    jit_patch_at(jump, load);
		}
	    }
	    if (next)
		jit_patch(next);
	    if (kind & (ri32|ri64|ru64|rf32|rf64))
		emit_sync();
	    switch (east_node(ast0)->code) {
		case eop_ne:	jit_calli(evm_ne);	break;
		case eop_lt:	jit_calli(evm_lt);	break;
		case eop_le:	jit_calli(evm_le);	break;
		case eop_eq:	jit_calli(evm_eq);	break;
		case eop_ge:	jit_calli(evm_ge);	break;
		default:	jit_calli(evm_gt);	break;
	    }
	    if (load)
		jit_link(load);
	    load_ireg32_implicit();
#  if __WORDSIZE == 32
	    jit_movi(JIT_V2, 0);
#  endif
	    if (done)
		jit_link(done);
	    ejit_sync = ejit_sync_register|ejit_sync_implicit|ejit_sync_int_ext;
	    break;
    }
    ejit_type = ast0->itype;
}

static void
emit_cmp_jmp(east_list_t *ast0, east_list_t *ast1)
{
    ecode_t		 code;
    jit_node_t		*done;
    jit_node_t		*jint;
    jit_node_t		*jflt;
    jit_node_t		*jmpz;
    jit_node_t		*jump;
    jit_node_t		*next;
    jit_node_t		*temp;
    eint32_t		 kind;
    elabel_t		*label;
    eword_t		 index;

    jmpz = null;
    if (east_node(ast1)->code == eop_jt)
	code = east_node(ast0)->code;
    else {
	switch (east_node(ast0)->code) {
	    case eop_lt:	code = eop_ge;		break;
	    case eop_le:	code = eop_gt;		break;
	    case eop_eq:	code = eop_ne;		break;
	    case eop_ge:	code = eop_lt;		break;
	    case eop_gt:	code = eop_le;		break;
	    default:		code = eop_eq;		break;
	}
    }
    label = east_node(ast1)->clabel.label;
    if (label->value == null)
	allocate_forward_label(label);
    index = eget_fixnum(label->value);
    switch (ast0->ltype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    kind = li32;		break;
	case t_uint32:	case t_int:
	    kind = li64;		break;
	case t_float:
	    kind = lf64;		break;
	case t_exact:
	    kind = lint;		break;
	case t_inexact:
	    kind = lrel;		break;
	case t_dynamic:
	    kind = lint|lrel;		break;
	default:
	    kind = 0;			break;
    }
    switch (ast0->rtype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    kind |= ri32;		break;
	case t_uint32:	case t_int:
	    kind |= ri64;		break;
	case t_uint:
	    kind |= ru64;		break;
	case t_float32:
	    kind |= rf32;		break;
	case t_float:
	    kind |= rf64;		break;
	case t_exact:
	    kind |= rint;		break;
	case t_inexact:
	    kind |= lrel;		break;
	case t_dynamic:
	    kind |= rint|rrel;		break;
	default:			break;
    }
    switch (kind) {
	case li32|ri32:
	    load_stack();
	    maybe_reload_ireg32_implicit();
	    jit_ldxi_i(JIT_R0, JIT_R1,
		       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		       offsetof(edata_t, s.l));
	    pop_stack();
	    switch (code) {
		case eop_lt:	jump = jit_bltr(JIT_R0, JIT_V1);	break;
		case eop_le:	jump = jit_bler(JIT_R0, JIT_V1);	break;
		case eop_eq:	jump = jit_beqr(JIT_R0, JIT_V1);	break;
		case eop_ge:	jump = jit_bger(JIT_R0, JIT_V1);	break;
		case eop_gt:	jump = jit_bgtr(JIT_R0, JIT_V1);	break;
		default:	jump = jit_bner(JIT_R0, JIT_V1);	break;
	    }
	    if (index >= 0)	jit_patch_at(jump, labels[index]);
	    else		record_forward_patch(jump, -index);
	    break;
	case li32|ri64:		case li64|ri32:		case li64|ri64:
	case li32|ru64:		case li64|ru64:
	    load_stack();
	    maybe_reload_extend_ireg_implicit(ast0->rtype);
	    if (kind & ru64) {
#  if __WORDSIZE == 32
		next = jit_bgei(JIT_V2, 0);
		store_ireg_implicit_rgz(RGZ_r1_pop_to_v1, JIT_V1, JIT_V2);
#  else
		next = jit_bgei(JIT_V1, 0);
		store_ireg_implicit_rgz(RGZ_r1_pop_to_v1, JIT_V1);
#  endif
		jit_prepare(jit_call_default);
		jit_pushargr(JIT_V1);
		switch (code) {
		    case eop_lt:	jit_finishi(evm_z_lt);		break;
		    case eop_le:	jit_finishi(evm_z_le);		break;
		    case eop_eq:	jit_finishi(evm_z_eq);		break;
		    case eop_ge:	jit_finishi(evm_z_ge);		break;
		    case eop_gt:	jit_finishi(evm_z_gt);		break;
		    default:		jit_finishi(evm_z_ne);		break;
		}
		jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
		load_ireg32_implicit();
		jump = jit_bnei(JIT_V1, 0);
		if (index >= 0)
		    jit_patch_at(jump, labels[index]);
		else
		    record_forward_patch(jump, -index);
		jmpz = jit_jmpi();
		jit_patch(next);
	    }
#  if __WORDSIZE == 32
	    jit_ldxi_i(JIT_R0, JIT_R1,
		       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		       offsetof(edata_t, s.l));
	    jit_ldxi_i(JIT_R2, JIT_R1,
		       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		       offsetof(edata_t, s.h));
	    pop_stack();
	    switch (code) {
		case eop_lt:
		    jump = jit_bltr(JIT_R2, JIT_V2);
		    temp = jit_bgtr(JIT_R2, JIT_V2);
		    if (index >= 0)	jit_patch_at(jump, labels[index]);
		    else		record_forward_patch(jump, -index);
		    jump = jit_bltr_u(JIT_R0, JIT_V1);
		    jit_patch(temp);
		    break;
		case eop_le:
		    jump = jit_bgtr(JIT_V2, JIT_R2);
		    temp = jit_bltr(JIT_V2, JIT_R2);
		    if (index >= 0)	jit_patch_at(jump, labels[index]);
		    else		record_forward_patch(jump, -index);
		    jump = jit_bler_u(JIT_R0, JIT_V1);
		    jit_patch(temp);
		    break;
		case eop_eq:
		    temp = jit_bner(JIT_V1, JIT_R0);
		    jump = jit_beqr(JIT_V2, JIT_R2);
		    jit_patch(temp);
		    break;
		case eop_ge:
		    jump = jit_bltr(JIT_V2, JIT_R2);
		    temp = jit_bgtr(JIT_V2, JIT_R2);
		    if (index >= 0)	jit_patch_at(jump, labels[index]);
		    else		record_forward_patch(jump, -index);
		    jump = jit_bger_u(JIT_R0, JIT_V1);
		    jit_patch(temp);
		    break;
		case eop_gt:
		    jump = jit_bgtr(JIT_R2, JIT_V2);
		    temp = jit_bltr(JIT_R2, JIT_V2);
		    if (index >= 0)	jit_patch_at(jump, labels[index]);
		    else		record_forward_patch(jump, -index);
		    jump = jit_bgtr_u(JIT_R0, JIT_V1);
		    jit_patch(temp);
		    break;
		default:
		    jump = jit_bner(JIT_V1, JIT_R0);
		    if (index >= 0)	jit_patch_at(jump, labels[index]);
		    else		record_forward_patch(jump, -index);
		    jump = jit_bner(JIT_V2, JIT_R2);
		    break;
	    }
#  else
	    jit_ldxi(JIT_R0, JIT_R1,
		     -sizeof(evalue_t) + offsetof(evalue_t, v.i));
	    pop_stack();
	    switch (code) {
		case eop_lt:	jump = jit_bltr(JIT_R0, JIT_V1);	break;
		case eop_le:	jump = jit_bler(JIT_R0, JIT_V1);	break;
		case eop_eq:	jump = jit_beqr(JIT_R0, JIT_V1);	break;
		case eop_ge:	jump = jit_bger(JIT_R0, JIT_V1);	break;
		case eop_gt:	jump = jit_bgtr(JIT_R0, JIT_V1);	break;
		default:	jump = jit_bner(JIT_R0, JIT_V1);	break;
	    }
#  endif
	    if (index >= 0)	jit_patch_at(jump, labels[index]);
	    else		record_forward_patch(jump, -index);
	    if (jmpz)
		jit_patch(jmpz);
	    break;
	case li32|rf32:		case li32|rf64:
	    load_stack();
	    if (kind & rf32) {
		if (!(ejit_sync & ejit_sync_register))
		    load_freg_implicit();
		else if (!(ejit_sync & ejit_sync_float_ext))
		    jit_extr_f_d(JIT_F0, JIT_F1);
	    }
	    else
		maybe_reload_freg_implicit();
	    jit_ldxi_i(JIT_R0, JIT_R1,
		       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		       offsetof(edata_t, s.l));
	    jit_extr_d(JIT_F2, JIT_R0);
	    goto float_float;
	case li64|rf32:		case li64|rf64:
	    load_stack();
#  if __WORDSIZE == 32
	    if (!(ejit_sync & ejit_sync_implicit)) {
		assert(ejit_sync & ejit_sync_register);
		if ((kind & rf32) && !(ejit_sync & ejit_sync_float_ext))
		    jit_extr_f_d(JIT_F0, JIT_F1);
		store_freg_implicit(true);
	    }
	    jit_prepare(jit_call_default);
	    jit_subi(JIT_V2, JIT_R1, sizeof(evalue_t));
	    jit_pushargr(JIT_V2);
	    switch (code) {
		case eop_lt:		jit_finishi(evm_d_lt);		break;
		case eop_le:		jit_finishi(evm_d_le);		break;
		case eop_eq:		jit_finishi(evm_d_eq);		break;
		case eop_ge:		jit_finishi(evm_d_ge);		break;
		case eop_gt:		jit_finishi(evm_d_gt);		break;
		default:		jit_finishi(evm_d_ne);		break;
	    }
	    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V2);
	    load_ireg32_implicit();
	    jump = jit_bnei(JIT_V1, 0);
	    if (index >= 0)
		jit_patch_at(jump, labels[index]);
	    else
		record_forward_patch(jump, -index);
	    break;
#  else
	    if (kind & rf32) {
		if (!(ejit_sync & ejit_sync_register))
		    load_freg_implicit();
		else if (!(ejit_sync & ejit_sync_float_ext))
		    jit_extr_f_d(JIT_F0, JIT_F1);
	    }
	    else
		maybe_reload_freg_implicit();
	    jit_ldxi(JIT_R0, JIT_R1,
		     -sizeof(evalue_t) + offsetof(evalue_t, v.i));
	    jit_extr_d(JIT_F2, JIT_R0);
	    goto float_float;
#  endif
	case lf64|ri32:
	    load_stack();
	    maybe_reload_ireg32_implicit();
	    jit_extr_d(JIT_F0, JIT_V1);
	    goto load_float_float;
	case lf64|ri64:		case lf64|ru64:
	    load_stack();
	    maybe_reload_extend_ireg_implicit(ast0->rtype);
	    if (kind & ru64) {
#  if __WORDSIZE == 32
		next = jit_bgei(JIT_V2, 0);
		store_ireg_implicit_rgz(RGZ_r1_pop_to_v1, JIT_V1, JIT_V2);
#  else
		next = jit_bgei(JIT_V1, 0);
		store_ireg_implicit_rgz(RGZ_r1_pop_to_v1, JIT_V1);
#  endif
		jit_prepare(jit_call_default);
		jit_pushargr(JIT_V1);
		switch (code) {
		    case eop_lt:	jit_finishi(evm_z_lt);		break;
		    case eop_le:	jit_finishi(evm_z_le);		break;
		    case eop_eq:	jit_finishi(evm_z_eq);		break;
		    case eop_ge:	jit_finishi(evm_z_ge);		break;
		    case eop_gt:	jit_finishi(evm_z_gt);		break;
		    default:		jit_finishi(evm_z_ne);		break;
		}
		jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
		load_ireg32_implicit();
		jump = jit_bnei(JIT_V1, 0);
		if (index >= 0)
		    jit_patch_at(jump, labels[index]);
		else
		    record_forward_patch(jump, -index);
		jmpz = jit_jmpi();
		jit_patch(next);
	    }
#  if __WORDSIZE == 32
	    if (!(ejit_sync & ejit_sync_implicit))
		store_ireg_implicit(true);
	    jit_addi(JIT_R0, JIT_V0, offsetof(ethread_t, r0) +
		     offsetof(evalue_t, v.d));
	    jit_prepare(jit_call_default);
	    jit_pushargr(JIT_R0);
	    jit_finishi(evm_store_float64);
	    load_freg_implicit();
#  else
	    jit_extr_d(JIT_F0, JIT_V1);
#  endif
	    goto load_float_float;
	case lf64|rf32:
	    load_stack();
	    if (!(ejit_sync & ejit_sync_register))
		load_freg_implicit();
	    else if (!(ejit_sync & ejit_sync_float_ext))
		jit_extr_f_d(JIT_F0, JIT_F1);
	    goto load_float_float;
	case lf64|rf64:
	    load_stack();
	    maybe_reload_freg_implicit();
	load_float_float:
	    jit_ldxi_d(JIT_F2, JIT_R1,
		       -sizeof(evalue_t) + offsetof(evalue_t, v.d));
	float_float:
	    pop_stack();
	    switch (code) {
		case eop_lt:	jump = jit_bltr_d(JIT_F2, JIT_F0);break;
		case eop_le:	jump = jit_bler_d(JIT_F2, JIT_F0);break;
		case eop_eq:	jump = jit_beqr_d(JIT_F2, JIT_F0);break;
		case eop_ge:	jump = jit_bger_d(JIT_F2, JIT_F0);break;
		case eop_gt:	jump = jit_bgtr_d(JIT_F2, JIT_F0);break;
		default:	jump = jit_bner_d(JIT_F2, JIT_F0);break;
	    }
	    if (index >= 0)	jit_patch_at(jump, labels[index]);
	    else		record_forward_patch(jump, -index);
	    if (jmpz)
		jit_patch(jmpz);
	    break;
	default:
	    jint = jflt = next = null;
	    if (kind & (ri32|ri64|ru64|rint|rf32|rf64|rrel)) {
		load_stack();
		done = jit_forward();
		if (kind & (rint|rrel))
		    jit_ldxi_i(JIT_R0, JIT_V0,
			       offsetof(ethread_t, r0) + offsetof(evalue_t, t));
	    }
	    else
		done = null;
	    if (kind & (ri32|ri64|ru64|rint)) {
		if (!(kind & (ri32|ri64|ru64)))
		    next = jit_bnei(JIT_R0, t_int);
		if (!(ejit_sync & ejit_sync_register))
		    load_ireg_implicit();
		else if ((kind & ri32) && !(ejit_sync & ejit_sync_int_ext))
		    zero_sign_extend(ast0->rtype);
		if (kind & ru64) {
		    jmpz = jit_forward();
#  if __WORDSIZE == 32
		    jump = jit_blti(JIT_V2, 0);
#  else
		    jump = jit_blti(JIT_V1, 0);
#  endif
		    jit_patch_at(jump, jmpz);
		}
		if (!(kind & (li32|li64))) {
		    jint = jit_forward();
		    jit_ldxi_i(JIT_R0, JIT_R1,
			       -sizeof(evalue_t) + offsetof(evalue_t, t));
		    if (
#  if __WORDSIZE == 32
			(kind & li32)
#  else
			(kind & (li32|li64|lint))
#  endif
			) {
			temp = jit_beqi(JIT_R0, t_int);
			jump = jit_bnei(JIT_R0, t_float);
			jit_patch_at(jump, jint);
			jit_extr_d(JIT_F0, JIT_V1);
			jit_ldxi_d(JIT_F2, JIT_R1,
				   -sizeof(evalue_t) + offsetof(evalue_t, v.d));
			pop_stack();
			switch (code) {
			    case eop_lt:
				jump = jit_bltr_d(JIT_F2, JIT_F0);	break;
			    case eop_le:
				jump = jit_bler_d(JIT_F2, JIT_F0);	break;
			    case eop_eq:
				jump = jit_beqr_d(JIT_F2, JIT_F0);	break;
			    case eop_ge:
				jump = jit_bger_d(JIT_F2, JIT_F0);	break;
			    case eop_gt:
				jump = jit_bgtr_d(JIT_F2, JIT_F0);	break;
			    default:
				jump = jit_bner_d(JIT_F2, JIT_F0);	break;
			}
			if (index >= 0)
			    jit_patch_at(jump, labels[index]);
			else
			    record_forward_patch(jump, -index);
			jump = jit_jmpi();
			jit_patch_at(jump, done);
			jit_patch(temp);
		    }
		    else {
			jump = jit_bnei(JIT_R0, t_int);
			jit_patch_at(jump, jint);
		    }
		}
#  if __WORDSIZE == 32
		jit_ldxi_i(JIT_R0, JIT_R1,
			   -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
			   offsetof(edata_t, s.l));
		jit_ldxi_i(JIT_R2, JIT_R1,
			   -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
			   offsetof(edata_t, s.h));
		pop_stack();
		switch (code) {
		    case eop_lt:
			jump = jit_bltr(JIT_R2, JIT_V2);
			temp = jit_bgtr(JIT_R2, JIT_V2);
			if (index >= 0)	jit_patch_at(jump, labels[index]);
			else		record_forward_patch(jump, -index);
			jump = jit_bltr_u(JIT_R0, JIT_V1);
			jit_patch(temp);
			break;
		    case eop_le:
			jump = jit_bgtr(JIT_V2, JIT_R2);
			temp = jit_bltr(JIT_V2, JIT_R2);
			if (index >= 0)	jit_patch_at(jump, labels[index]);
			else		record_forward_patch(jump, -index);
			jump = jit_bler_u(JIT_R0, JIT_V1);
			jit_patch(temp);
			break;
		    case eop_eq:
			temp = jit_bner(JIT_V1, JIT_R0);
			jump = jit_beqr(JIT_V2, JIT_R2);
			jit_patch(temp);
			break;
		    case eop_ge:
			jump = jit_bltr(JIT_V2, JIT_R2);
			temp = jit_bgtr(JIT_V2, JIT_R2);
			if (index >= 0)	jit_patch_at(jump, labels[index]);
			else		record_forward_patch(jump, -index);
			jump = jit_bger_u(JIT_R0, JIT_V1);
			jit_patch(temp);
			break;
		    case eop_gt:
			jump = jit_bgtr(JIT_R2, JIT_V2);
			temp = jit_bltr(JIT_R2, JIT_V2);
			if (index >= 0)	jit_patch_at(jump, labels[index]);
			else		record_forward_patch(jump, -index);
			jump = jit_bgtr_u(JIT_R0, JIT_V1);
			jit_patch(temp);
			break;
		    default:
			jump = jit_bner(JIT_V1, JIT_R0);
			if (index >= 0)	jit_patch_at(jump, labels[index]);
			else		record_forward_patch(jump, -index);
			jump = jit_bner(JIT_V2, JIT_R2);
			break;
		}
#  else
		jit_ldxi(JIT_R0, JIT_R1,
			 -sizeof(evalue_t) + offsetof(evalue_t, v.i));
		pop_stack();
		switch (code) {
		    case eop_lt:jump = jit_bltr(JIT_R0, JIT_V1);	break;
		    case eop_le:jump = jit_bler(JIT_R0, JIT_V1);	break;
		    case eop_eq:jump = jit_beqr(JIT_R0, JIT_V1);	break;
		    case eop_ge:jump = jit_bger(JIT_R0, JIT_V1);	break;
		    case eop_gt:jump = jit_bgtr(JIT_R0, JIT_V1);	break;
		    default:	jump = jit_bner(JIT_R0, JIT_V1);	break;
		}
#  endif
		if (index >= 0)		jit_patch_at(jump, labels[index]);
		else			record_forward_patch(jump, -index);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
		if (jint) {
		    jit_link(jint);
		    if (!(ejit_sync & ejit_sync_implicit))
			store_ireg_implicit(true);
		    jit_prepare(jit_call_default);
		    jit_subi(JIT_V2, JIT_R1, sizeof(evalue_t));
		    jit_pushargr(JIT_V2);
		    switch (code) {
			case eop_lt:	jit_finishi(evm_i_lt);		break;
			case eop_le:	jit_finishi(evm_i_le);		break;
			case eop_eq:	jit_finishi(evm_i_eq);		break;
			case eop_ge:	jit_finishi(evm_i_ge);		break;
			case eop_gt:	jit_finishi(evm_i_gt);		break;
			default:	jit_finishi(evm_i_ne);		break;
		    }
		    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V2);
		    load_ireg32_implicit();
		    jump = jit_bnei(JIT_V1, 0);
		    if (index >= 0)
			jit_patch_at(jump, labels[index]);
		    else
			record_forward_patch(jump, -index);
		    jump = jit_jmpi();
		    jit_patch_at(jump, done);
		}
		if (jmpz) {
		    jit_link(jmpz);
#  if __WORDSIZE == 32
		    store_ireg_implicit_rgz(RGZ_r1_pop_to_v1, JIT_V1, JIT_V2);
#  else
		    store_ireg_implicit_rgz(RGZ_r1_pop_to_v1, JIT_V1);
#  endif
		    jit_prepare(jit_call_default);
		    jit_pushargr(JIT_V1);
		    switch (code) {
			case eop_lt:	jit_finishi(evm_z_lt);		break;
			case eop_le:	jit_finishi(evm_z_le);		break;
			case eop_eq:	jit_finishi(evm_z_eq);		break;
			case eop_ge:	jit_finishi(evm_z_ge);		break;
			case eop_gt:	jit_finishi(evm_z_gt);		break;
			default:	jit_finishi(evm_z_ne);		break;
		    }
		    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
		    load_ireg32_implicit();
		    jump = jit_bnei(JIT_V1, 0);
		    if (index >= 0)
			jit_patch_at(jump, labels[index]);
		    else
			record_forward_patch(jump, -index);
		    jump = jit_jmpi();
		    jit_patch_at(jump, done);
		}
	    }
	    if (kind & (rf32|rf64|rrel)) {
		jump = null;
		if (next)
		    jit_patch(next);
		if (!(kind & (rf32|rf64)))
		    next = jit_bnei(JIT_R0, t_float);
		if (!(ejit_sync & ejit_sync_register))
		    load_freg_implicit();
		else if ((kind & rf32) && !(ejit_sync & ejit_sync_float_ext))
		    jit_extr_f_d(JIT_F0, JIT_F1);
		if (!(kind & lf64)) {
		    jflt = jit_forward();
		    jit_ldxi_i(JIT_R0, JIT_R1,
			       -sizeof(evalue_t) + offsetof(evalue_t, t));
		    if (
#  if __WORDSIZE == 32
			(kind & li32)
#  else
			(kind & (li32|li64|lint))
#  endif
			) {
			temp = jit_beqi(JIT_R0, t_float);
			jump = jit_bnei(JIT_R0, t_int);
			jit_patch_at(jump, jflt);
#  if __WORDSIZE == 32
			jit_ldxi_i(JIT_R2, JIT_R1,
				   -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
				   offsetof(edata_t, s.l));
#  else
			jit_ldxi(JIT_R2, JIT_R1,
				 -sizeof(evalue_t) + offsetof(evalue_t, v.i));
#  endif
			jit_extr_d(JIT_F2, JIT_R2);
			jump = jit_jmpi();
			jit_patch(temp);
		    }
		    else {
			temp = jit_bnei(JIT_R0, t_float);
			jit_patch_at(temp, jflt);
		    }
		}
		jit_ldxi_d(JIT_F2, JIT_R1,
			   -sizeof(evalue_t) + offsetof(evalue_t, v.d));
		if (jump)
		    jit_patch(jump);
		pop_stack();
		switch (code) {
		    case eop_lt:jump = jit_bltr_d(JIT_F2, JIT_F0);	break;
		    case eop_le:jump = jit_bler_d(JIT_F2, JIT_F0);	break;
		    case eop_eq:jump = jit_beqr_d(JIT_F2, JIT_F0);	break;
		    case eop_ge:jump = jit_bger_d(JIT_F2, JIT_F0);	break;
		    case eop_gt:jump = jit_bgtr_d(JIT_F2, JIT_F0);	break;
		    default:	jump = jit_bner_d(JIT_F2, JIT_F0);	break;
		}
		if (index >= 0)
		    jit_patch_at(jump, labels[index]);
		else
		    record_forward_patch(jump, -index);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
		if (jflt) {
		    jit_link(jflt);
		    if (!(ejit_sync & ejit_sync_implicit))
			store_freg_implicit(true);
		    jit_prepare(jit_call_default);
		    jit_subi(JIT_V2, JIT_R1, sizeof(evalue_t));
		    jit_pushargr(JIT_V2);
		    switch (code) {
			case eop_lt:	jit_finishi(evm_d_lt);		break;
			case eop_le:	jit_finishi(evm_d_le);		break;
			case eop_eq:	jit_finishi(evm_d_eq);		break;
			case eop_ge:	jit_finishi(evm_d_ge);		break;
			case eop_gt:	jit_finishi(evm_d_gt);		break;
			default:	jit_finishi(evm_d_ne);		break;
		    }
		    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V2);
		    load_ireg32_implicit();
		    jump = jit_bnei(JIT_V1, 0);
		    if (index >= 0)
			jit_patch_at(jump, labels[index]);
		    else
			record_forward_patch(jump, -index);
		    jump = jit_jmpi();
		    jit_patch_at(jump, done);
		}
	    }
	    if (next)
		jit_patch(next);
	    if (kind & (ri32|ri64|ru64|rf32|rf64))
		emit_sync();
	    switch (code) {
		case eop_lt:	jit_finishi(evm_lt);		break;
		case eop_le:	jit_finishi(evm_le);		break;
		case eop_eq:	jit_finishi(evm_eq);		break;
		case eop_ge:	jit_finishi(evm_ge);		break;
		case eop_gt:	jit_finishi(evm_gt);		break;
		default:	jit_finishi(evm_ne);		break;
	    }
	    load_ireg32_implicit();
	    jump = jit_bnei(JIT_V1, 0);
	    if (index >= 0)
		jit_patch_at(jump, labels[index]);
	    else
		record_forward_patch(jump, -index);
	    if (done)
		jit_link(done);
	    break;
    }
    emit_clear();
}

static void
emit_addsub(east_list_t *ast0)
{
    jit_node_t		*done;
    jit_node_t		*jump;
    jit_node_t		*next;
    jit_node_t		*over;
    jit_node_t		*jext;
    eint32_t		 kind;
    jit_int32_t		 lreg;
    jit_int32_t		 rreg;
#  if __WORDSIZE == 32
    jit_int32_t		 hlreg;
    jit_int32_t		 hrreg;
#  endif
    jit_node_t		*check;
    ebool_t		 doint;
    ebool_t		 doflt;

    switch (ast0->ltype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    kind = li32;		break;
	case t_uint32:	case t_int:
	    kind = li64;		break;
	case t_float:
	    kind = lf64;		break;
	case t_exact:
	    kind = lint;		break;
	case t_inexact:
	    kind = lrel;		break;
	case t_dynamic:
	    kind = lint|lrel;		break;
	default:
	    kind = 0;			break;
    }
    switch (ast0->rtype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    kind |= ri32;		break;
	case t_uint32:	case t_int:
	    kind |= ri64;		break;
	case t_uint:
	    kind |= ru64;		break;
	case t_float32:
	    kind |= rf32;		break;
	case t_float:
	    kind |= rf64;		break;
	case t_exact:
	    kind |= rint;		break;
	case t_inexact:
	    kind |= rrel;		break;
	case t_dynamic:
	    kind |= rint|rrel;		break;
	default:			break;
    }
    switch (ast0->itype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    kind |= ii32;		break;
	case t_int:
	    kind |= ii64;		break;
	case t_float:
	    kind |= if64;		break;
	case t_exact:
	    kind |= iint;		break;
	case t_inexact:
	    kind |= irel;		break;
	case t_dynamic:
	    kind |= iint|irel;		break;
	default:			break;
    }
    switch (kind) {
	case li32|ri32|ii32:
	    maybe_reload_ireg32_implicit();
	    goto int_int_int;
	case li32|ri32|ii64:	case li32|ri64|ii64:
	case li64|ri32|ii64:	case li64|ri64|ii64:
	    maybe_reload_extend_ireg_implicit(ast0->rtype);
	int_int_int:
	    load_stack();
	    if (JIT_NUM_OPERANDS == 2) {
		lreg = JIT_V1;			rreg = JIT_R0;
		jit_movr(JIT_R0, JIT_V1);
	    }
	    else {
		lreg = JIT_R0;			rreg = JIT_V1;
	    }
#  if __WORDSIZE == 32
	    jit_ldxi(lreg, JIT_R1,
		     -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		     offsetof(edata_t, s.l));
	    if (kind & ii64) {
		if (JIT_NUM_OPERANDS == 2) {
		    hlreg = JIT_V2;		hrreg = JIT_R2;
		    jit_movr(JIT_R2, JIT_V2);
		}
		else {
		    hlreg = JIT_R2;		hrreg = JIT_V2;
		}
		if (kind & li64) {
		    jit_ldxi(hlreg, JIT_R1,
			     -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
			     offsetof(edata_t, s.h));
		}
		else
		    jit_rshi(hlreg, lreg, 31);
		if (east_node(ast0)->code == eop_add) {
		    jit_addcr(JIT_V1, lreg, rreg);
		    jit_addxr(JIT_V2, hlreg, hrreg);
		}
		else {
		    jit_subcr(JIT_V1, lreg, rreg);
		    jit_subxr(JIT_V2, hlreg, hrreg);
		}
	    }
	    else {
		if (east_node(ast0)->code == eop_add)
		    jit_addr(JIT_V1, lreg, rreg);
		else
		    jit_subr(JIT_V1, lreg, rreg);
	    }
#  else
	    if (kind & li32)
		jit_ldxi_i(lreg, JIT_R1,
			   -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
			   offsetof(edata_t, s.l));
	    else
		jit_ldxi(lreg, JIT_R1,
			 -sizeof(evalue_t) + offsetof(evalue_t, v.i));
	    if (east_node(ast0)->code == eop_add)
		jit_addr(JIT_V1, lreg, rreg);
	    else
		jit_subr(JIT_V1, lreg, rreg);
#  endif
	    pop_stack();
	    ejit_sync = ejit_sync_register;
	    if (kind & ii64)
		ejit_sync |= ejit_sync_int_ext;
	    break;
	case li32|ri64|iint:	case li32|ru64|iint:
	case li64|ri32|iint:	case li64|ri64|iint:	case li64|ru64|iint:
	case lint|ri32|iint:	case lint|ri64|iint:	case lint|ru64|iint:
	    done = jit_forward();
	    maybe_reload_extend_ireg_implicit(ast0->rtype);
	    load_stack();
	    if (kind & ru64) {
#  if __WORDSIZE == 32
		next = jit_bgei(JIT_V2, 0);
		store_ireg_implicit_rgz(RGZ_r1_pop_to_v1, JIT_V1, JIT_V2);
#  else
		next = jit_bgei(JIT_V1, 0);
		store_ireg_implicit_rgz(RGZ_r1_pop_to_v1, JIT_V1);
#  endif
		jit_prepare(jit_call_default);
		jit_pushargr(JIT_V1);
		if (east_node(ast0)->code == eop_add)
		    jit_finishi(evm_z_add);
		else
		    jit_finishi(evm_z_sub);
		jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
		/* simplify logic by reloading if int[+-]mpz results in int */
		jit_ldxi_i(JIT_R0, JIT_V0,
			   offsetof(ethread_t, r0) + offsetof(evalue_t, t));
		jump = jit_bnei(JIT_R0, t_int);
		jit_patch_at(jump, done);
		load_ireg_implicit();
		jump = jit_jmpi();
		jit_patch_at(jump, done);
		jit_patch(next);
	    }
	    if (!(ejit_sync & ejit_sync_implicit)) {
		assert(ejit_sync & ejit_sync_register);
		store_ireg_implicit(true);
	    }
	    /* overflow target */
	    over = jit_forward();
	    if (kind & lint) {
		jit_ldxi_i(JIT_R0, JIT_R1,
			   -sizeof(evalue_t) + offsetof(evalue_t, t));
		jump = jit_bnei(JIT_R0, t_int);
		/* not really overflow, just call vm if not an integer */
		jit_patch_at(jump, over);
	    }
	    jit_movr(JIT_R0, JIT_V1);
#  if __WORDSIZE == 32
	    /* FIXME
	     * This should be better done by adding the new jit interfaces:
	     *	jit_boaddxr, jit_bxaddxr, jit_bosubxr, jit_bxsubxr
	     * and the related unsigned variants for completeness
	     * as this would better map to hardware, or, be basically
	     * a noop in the worst case. The code below then would be
	     * written somewhat like:
	     *	jit_addcr(JIT_V1, JIT_V1, <low-word>);
	     *	jit_boaddxr(JIT_V2, JIT_V2, <high-word>);
	     */
	    /* load low word */
	    jit_ldxi(JIT_V1, JIT_R1,
		     -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		     offsetof(edata_t, s.l));
	    jit_movr(JIT_R2, JIT_V1);
	    /* compute low word and carry */
	    if (east_node(ast0)->code == eop_add) {
		jit_addr(JIT_V1, JIT_V1, JIT_R0);
		jit_ltr_u(JIT_R0, JIT_V1, JIT_R2);
	    }
	    else {
		jit_subr(JIT_V1, JIT_V1, JIT_R0);
		jit_gtr_u(JIT_R0, JIT_V1, JIT_R2);
	    }
	    /* abort if carry causes overflow in high word */
	    jump = jit_boaddr(JIT_V2, JIT_R0);
	    jit_patch_at(jump, over);
	    jit_movr(JIT_R2, JIT_V2);
	    /* load high word */
	    jit_ldxi(JIT_V2, JIT_R1,
		     -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		     offsetof(edata_t, s.h));
	    if (east_node(ast0)->code == eop_add)
		jump = jit_boaddr(JIT_V2, JIT_R2);
	    else
		jump = jit_bosubr(JIT_V2, JIT_R2);
#  else
	    jit_ldxi(JIT_V1, JIT_R1,
		     -sizeof(evalue_t) + offsetof(evalue_t, v.i));
	    if (east_node(ast0)->code == eop_add)
		jump = jit_boaddr(JIT_V1, JIT_R0);
	    else
		jump = jit_bosubr(JIT_V1, JIT_R0);
#  endif
	    jit_patch_at(jump, over);
	    store_ireg_implicit(false);
	    pop_stack();
	    jump = jit_jmpi();
	    jit_patch_at(jump, done);
	    jit_link(over);
	    jit_prepare(jit_call_default);
	    jit_subi(JIT_V2, JIT_R1, sizeof(evalue_t));
	    jit_pushargr(JIT_V2);
	    if (east_node(ast0)->code == eop_add)
		jit_finishi(evm_i_add);
	    else
		jit_finishi(evm_i_sub);
	    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V2);
	    DEBUG_IMPLICIT_TYPE();
	    jit_link(done);
	    ejit_sync = ejit_sync_register|ejit_sync_dynamic|
			ejit_sync_implicit|ejit_sync_int_ext;
	    break;
	case li32|rf32|if64:
	    if (!(ejit_sync & ejit_sync_register))
		load_freg_implicit();
	    else if (!(ejit_sync & ejit_sync_float_ext))
		jit_extr_f_d(JIT_F0, JIT_F1);
	    goto i32_f64_f64;
	case li32|rf64|if64:
	    if (!(ejit_sync & ejit_sync_register))
		load_freg_implicit();
	i32_f64_f64:
	    load_stack();
	    jit_ldxi_i(JIT_R0, JIT_R1,
		       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		       offsetof(edata_t, s.l));
	    jit_extr_d(JIT_F2, JIT_R0);
	    if (east_node(ast0)->code == eop_add)
		jit_addr_d(JIT_F0, JIT_F2, JIT_F0);
	    else
		jit_subr_d(JIT_F0, JIT_F2, JIT_F0);
	    pop_stack();
	    ejit_sync = ejit_sync_register;
	    break;
	case li64|rf32|if64:
	    if (!(ejit_sync & ejit_sync_register))
		load_freg_implicit();
	    else if (!(ejit_sync & ejit_sync_float_ext))
		jit_extr_f_d(JIT_F0, JIT_F1);
	    goto i64_f64_f64;
	case li64|rf64|if64:
	i64_f64_f64:
	    load_stack();
#  if __WORDSIZE == 32
	    if (!(ejit_sync & ejit_sync_implicit)) {
		assert(ejit_sync & ejit_sync_register);
		store_freg_implicit(true);
	    }
	    jit_prepare(jit_call_default);
	    jit_subi(JIT_V2, JIT_R1, sizeof(evalue_t));
	    jit_pushargr(JIT_V2);
	    if (east_node(ast0)->code == eop_add)
		jit_finishi(evm_d_add);
	    else
		jit_finishi(evm_d_sub);
	    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V2);
	    load_freg_implicit();
	    ejit_sync = ejit_sync_register|ejit_sync_implicit;
#  else
	    if (!(ejit_sync & ejit_sync_register))
		load_freg_implicit();
	    jit_ldxi(JIT_R0, JIT_R1,
		     -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		     offsetof(edata_t, s.l));
	    jit_extr_d(JIT_F2, JIT_R0);
	    if (east_node(ast0)->code == eop_add)
		jit_addr_d(JIT_F0, JIT_F2, JIT_F0);
	    else
		jit_subr_d(JIT_F0, JIT_F2, JIT_F0);
	    pop_stack();
	    ejit_sync = ejit_sync_register;
#  endif
	    break;
	case lf64|ri32|if64:
	    if (!(ejit_sync & ejit_sync_register)) {
		load_ireg32_implicit();
		jit_extr_d(JIT_F0, JIT_V1);
	    }
	    else if (!(ejit_sync & ejit_sync_int_double))
		jit_extr_d(JIT_F0, JIT_V1);
	    goto float_float_float;
	case lf64|ri64|if64:
#  if __WORDSIZE == 32
	    if (!(ejit_sync & ejit_sync_register))
		assert(ejit_sync & ejit_sync_implicit);
	    else if (!(ejit_sync & ejit_sync_implicit))
		store_ireg_implicit(true);
	    jit_addi(JIT_R0, JIT_V0, offsetof(ethread_t, r0) +
		     offsetof(evalue_t, v.d));
	    jit_prepare(jit_call_default);
	    jit_pushargr(JIT_R0);
	    jit_finishi(evm_store_float64);
	    load_freg_implicit();
#  else
	    if (!(ejit_sync & ejit_sync_register)) {
		load_ireg_implicit();
		jit_extr_d(JIT_F0, JIT_V1);
	    }
	    else if (!(ejit_sync & ejit_sync_int_double))
		jit_extr_d(JIT_F0, JIT_V1);
#  endif
	    goto float_float_float;
	case lf64|ru64|if64:
	    load_stack();
	    if (!(ejit_sync & ejit_sync_register)) {
		assert(ejit_sync & ejit_sync_implicit);
		load_ireg_implicit();
	    }
#  if __WORDSIZE == 32
	    next = jit_blti(JIT_V2, 0);
	    if (!(ejit_sync & ejit_sync_implicit))
		store_ireg_implicit(true);
	    jit_addi(JIT_R0, JIT_V0, offsetof(ethread_t, r0) +
		     offsetof(evalue_t, v.d));
	    jit_prepare(jit_call_default);
	    jit_pushargr(JIT_R0);
	    jit_finishi(evm_store_float64);
	    load_freg_implicit();
#  else
	    next = jit_blti(JIT_V1, 0);
	    jit_extr_d(JIT_F0, JIT_V1);
#  endif
	    jit_ldxi_d(JIT_F2, JIT_R1,
		       -sizeof(evalue_t) + offsetof(evalue_t, v.d));
	    if (east_node(ast0)->code == eop_add)
		jit_addr_d(JIT_F0, JIT_F2, JIT_F0);
	    else
		jit_subr_d(JIT_F0, JIT_F2, JIT_F0);
	    pop_stack();
	    done = jit_jmpi();
	    jit_patch(next);
#  if __WORDSIZE == 32
	    store_ireg_implicit_rgz(RGZ_r1_pop_to_v1, JIT_V1, JIT_V2);
#  else
	    store_ireg_implicit_rgz(RGZ_r1_pop_to_v1, JIT_V1);
#  endif
	    jit_prepare(jit_call_default);
	    jit_pushargr(JIT_V1);
	    if (east_node(ast0)->code == eop_add)
		jit_finishi(evm_z_add);
	    else
		jit_finishi(evm_z_sub);
	    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
	    load_freg_implicit();
	    jit_patch(done);
	    ejit_sync = ejit_sync_register|ejit_sync_implicit;
	    break;
	case lf64|rf32|if64:
	    if (!(ejit_sync & ejit_sync_register))
		load_freg_implicit();
	    else if (!(ejit_sync & ejit_sync_float_ext))
		jit_extr_f_d(JIT_F0, JIT_F1);
	    goto float_float_float;
	case lf64|rf64|if64:
	    if (!(ejit_sync & ejit_sync_register))
		load_freg_implicit();
	float_float_float:
	    load_stack();
	    jit_ldxi_d(JIT_F2, JIT_R1,
		       -sizeof(evalue_t) + offsetof(evalue_t, v.d));
	    if (east_node(ast0)->code == eop_add)
		jit_addr_d(JIT_F0, JIT_F2, JIT_F0);
	    else
		jit_subr_d(JIT_F0, JIT_F2, JIT_F0);
	    pop_stack();
	    ejit_sync = ejit_sync_register;
	    break;
	default:
	    if (kind & (lf64|rf32|rf64|if64))
		kind &= ~iint;
	    doint = ((kind & (ri32|ri64|ru64|rint)) &&
		     ((kind & (li32|li64|lint)) ||
		      (
#  if __WORDSIZE == 32
		       (kind & ri32)
#  else
		       (kind & (ri32|ri64|ru64|rint))
#  endif
		       && (kind & (lf64|lrel)))));
	    doflt = ((kind & (rf32|rf64|rrel)) &&
		     ((kind & (lf32|lf64|lrel)) ||
#  if __WORDSIZE == 32
		      (kind & li32)
#  else
		      (kind & (li32|li64|lint))
#  endif
		      ));
	    next = done = check = null;
	    if (doint || doflt) {
		load_stack();
		done = jit_forward();
		check = jit_forward();
		if (!(kind & (ri32|ri64|ru64|rf32|rf64)))
		    jit_ldxi_i(JIT_R0, JIT_V0,
			       offsetof(ethread_t, r0) + offsetof(evalue_t, t));
	    }
	    if (doint) {
		over = jit_forward();
		if (!(kind & (ri32|ri64|ru64)))
		    next = jit_bnei(JIT_R0, t_int);
		if (!(ejit_sync & ejit_sync_register))
		    load_ireg_implicit();
		else if ((kind & ri32) && !(ejit_sync & ejit_sync_int_ext))
		    zero_sign_extend(ast0->rtype);
		if (kind & ru64) {
#  if __WORDSIZE == 32
		    jext = jit_bgei(JIT_V2, 0);
		    store_ireg_implicit_rgz(RGZ_r1_pop_to_v1, JIT_V1, JIT_V2);
#  else
		    jext = jit_bgei(JIT_V1, 0);
		    store_ireg_implicit_rgz(RGZ_r1_pop_to_v1, JIT_V1);
#  endif
		    jit_prepare(jit_call_default);
		    jit_pushargr(JIT_V1);
		    if (east_node(ast0)->code == eop_add)
			jit_finishi(evm_z_add);
		    else
			jit_finishi(evm_z_sub);
		    jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
		    jump = jit_jmpi();
		    jit_patch_at(jump, check);
		    jit_patch(jext);
		}
		if (!(kind & (li32|li64))) {
		    if (
#  if __WORDSIZE == 32
			(kind & ri32)
#  else
			(kind & (ri32|ri64|ru64))
#  endif
			&& (kind & (lf64|lrel))) {
			jext = null;
			if (!(kind & lf64)) {
			    jit_ldxi_i(JIT_R0, JIT_R1,
				       -sizeof(evalue_t) +
				       offsetof(evalue_t, t));
			    if (kind & lint)
				jext = jit_beqi(JIT_R0, t_int);
			    jump = jit_bnei(JIT_R0, t_float);
			    jit_patch_at(jump, over);
			}
			jit_extr_d(JIT_F0, JIT_V1);
			jit_ldxi_d(JIT_F2, JIT_R1,
				   -sizeof(evalue_t) + offsetof(evalue_t, v.d));
			if (east_node(ast0)->code == eop_add)
			    jit_addr_d(JIT_F0, JIT_F2, JIT_F0);
			else
			    jit_subr_d(JIT_F0, JIT_F2, JIT_F0);
			store_freg_implicit(true);
			pop_stack();
			jump = jit_jmpi();
			jit_patch_at(jump, done);
			if (jext)
			    jit_patch(jext);
		    }
		    else {
			jump = jit_bnei(JIT_R0, t_int);
			jit_patch_at(jump, over);
		    }
		}
		if (!(ejit_sync & ejit_sync_implicit)) {
		    assert(ejit_sync & ejit_sync_register);
		    store_ireg_implicit(true);
		}
		jit_movr(JIT_R0, JIT_V1);
#  if __WORDSIZE == 32
		/* load low word */
		jit_ldxi(JIT_V1, JIT_R1,
			 -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
			 offsetof(edata_t, s.l));
		jit_movr(JIT_R2, JIT_V1);
		/* compute low word and carry */
		if (east_node(ast0)->code == eop_add) {
		    jit_addr(JIT_V1, JIT_V1, JIT_R0);
		    jit_ltr_u(JIT_R0, JIT_V1, JIT_R2);
		}
		else {
		    jit_subr(JIT_V1, JIT_V1, JIT_R0);
		    jit_gtr_u(JIT_R0, JIT_V1, JIT_R2);
		}
		/* abort if carry causes overflow in high word */
		jump = jit_boaddr(JIT_V2, JIT_R0);
		jit_patch_at(jump, over);
		jit_movr(JIT_R2, JIT_V2);
		/* load high word */
		jit_ldxi(JIT_V2, JIT_R1,
			 -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
			 offsetof(edata_t, s.h));
		if (east_node(ast0)->code == eop_add)
		    jump = jit_boaddr(JIT_V2, JIT_R2);
		else
		    jump = jit_bosubr(JIT_V2, JIT_R2);
#  else
		jit_ldxi(JIT_V1, JIT_R1,
			 -sizeof(evalue_t) + offsetof(evalue_t, v.i));
		if (east_node(ast0)->code == eop_add)
		    jump = jit_boaddr(JIT_V1, JIT_R0);
		else
		    jump = jit_bosubr(JIT_V1, JIT_R0);
#  endif
		jit_patch_at(jump, over);
		store_ireg_implicit(!(ejit_sync & ejit_sync_implicit));
		pop_stack();
		jump = jit_jmpi();
		jit_patch_at(jump, done);
		jit_link(over);
		if (!(ejit_sync & ejit_sync_implicit))
		    store_ireg_implicit(true);
		jit_prepare(jit_call_default);
		jit_subi(JIT_V2, JIT_R1, sizeof(evalue_t));
		jit_pushargr(JIT_V2);
		if (east_node(ast0)->code == eop_add)
		    jit_finishi(evm_i_add);
		else
		    jit_finishi(evm_i_sub);
		jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V2);
		jump = jit_jmpi();
		jit_patch_at(jump, check);
	    }
	    if (doflt) {
		jext = null;
		over = jit_forward();
		if (next)
		    jit_patch(next);
		if (!(kind & (rf32|rf64)))
		    next = jit_bnei(JIT_R0, t_float);
		else
		    next = null;
		if (!(ejit_sync & ejit_sync_register))
		    load_freg_implicit();
		else if ((kind & rf32) && !(ejit_sync & ejit_sync_float_ext))
		    jit_extr_f_d(JIT_F0, JIT_F1);
		if (!(kind & lf64)) {
		    if (
#  if __WORDSIZE == 32
			(kind & li32)
#  else
			(kind & (li32|li64|lint))
#  endif
			) {
			jump = null;
			if (kind & lint) {
			    jit_ldxi_i(JIT_R0, JIT_R1,
				       -sizeof(evalue_t) +
				       offsetof(evalue_t, t));
			    if (kind & lrel)
				jump = jit_beqi(JIT_R0, t_float);
			    jext = jit_bnei(JIT_R0, t_int);
			    jit_patch_at(jext, over);
			}
#  if __WORDSIZE == 32
			jit_ldxi_i(JIT_R2, JIT_R1,
				   -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
				   offsetof(edata_t, s.l));
#  else
			jit_ldxi(JIT_R2, JIT_R1,
				 -sizeof(evalue_t) + offsetof(evalue_t, v.i));
#  endif
			jit_extr_d(JIT_F2, JIT_R2);
			jext = jit_jmpi();
			if (jump)
			    jit_patch(jump);
		    }
		    else {
			jump = jit_bnei(JIT_R0, t_float);
			jit_patch_at(jump, over);
		    }
		}
		jit_ldxi_d(JIT_F2, JIT_R1,
			   -sizeof(evalue_t) + offsetof(evalue_t, v.d));
		if (jext)
		    jit_patch(jext);
		if (east_node(ast0)->code == eop_add)
		    jit_addr_d(JIT_F0, JIT_F2, JIT_F0);
		else
		    jit_subr_d(JIT_F0, JIT_F2, JIT_F0);
		store_freg_implicit(!(ejit_sync & ejit_sync_implicit));
		pop_stack();
		jump = jit_jmpi();
		jit_patch_at(jump, done);
		jit_link(over);
		if (!(ejit_sync & ejit_sync_implicit))
		    store_freg_implicit(true);
		jit_prepare(jit_call_default);
		jit_subi(JIT_V1, JIT_R1, sizeof(evalue_t));
		jit_pushargr(JIT_V1);
		if (east_node(ast0)->code == eop_add)
		    jit_finishi(evm_d_add);
		else
		    jit_finishi(evm_d_sub);
		jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
		jump = jit_jmpi();
		jit_patch_at(jump, check);
	    }
	    if (next)
		jit_patch(next);
	    if ((kind & (ri32|ri64|ru64|rf32|rf64)) &&
		(!(ejit_sync & ejit_sync_implicit)))
		emit_sync();
	    if (east_node(ast0)->code == eop_add)
		jit_calli(evm_add);
	    else
		jit_calli(evm_sub);
	    /* reload */
	    if (check)
		jit_link(check);
	    next = jump = null;
	    if (kind & (iint|irel))
		jit_ldxi_i(JIT_R0, JIT_V0,
			   offsetof(ethread_t, r0) + offsetof(evalue_t, t));
	    if (kind & iint) {
		next = jit_bnei(JIT_R0, t_int);
		load_ireg_implicit();
		jump = jit_jmpi();
	    }
	    else
		DEBUG_IMPLICIT_TYPE_INT();
	    if (kind & irel) {
		if (next)
		    jit_patch(next);
		next = jit_bnei(JIT_R0, t_float);
		load_freg_implicit();
	    }
	    else
		DEBUG_IMPLICIT_TYPE_FLOAT();
	    if (jump)
		jit_patch(jump);
	    if (next)
		jit_patch(next);
	    if (done)
		jit_link(done);
	    ejit_sync = ejit_sync_register|ejit_sync_implicit|
			ejit_sync_dynamic|ejit_sync_int_ext;
	    break;
    }
    ejit_type = ast0->itype;
}

static void
emit_andorxor(east_list_t *ast0)
{
    jit_node_t		*done;
    jit_node_t		*jint;
    jit_node_t		*jmpz;
    jit_node_t		*jump;
    jit_node_t		*next;
    jit_node_t		*temp;
    eint32_t		 kind;
    jit_node_t		*check;

    switch (ast0->ltype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    kind = li32;		break;
	case t_uint32:	case t_int:
	    kind = li64;		break;
	case t_exact:	case t_inexact:	case t_dynamic:
	    kind = lint;		break;
	default:
	    kind = 0;			break;
    }
    switch (ast0->rtype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    kind |= ri32;		break;
	case t_uint32:	case t_int:
	    kind |= ri64;		break;
	case t_uint:
	    kind |= ru64;		break;
	case t_exact:	case t_inexact:	case t_dynamic:
	    kind |= rint;		break;
	default:			break;
    }
    switch (ast0->itype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:
	    kind |= ii32;		break;
	case t_int:
	    kind |= ii64;		break;
	case t_exact:	case t_inexact:	case t_dynamic:
	    kind |= iint;		break;
	default:			break;
    }
    switch (kind) {
	case li32|ri32|ii32:
	    maybe_reload_ireg32_implicit();
	    load_stack();
	    jit_ldxi_i(JIT_R0, JIT_R1,
		       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		       offsetof(edata_t, s.l));
	    switch (east_node(ast0)->code) {
		case eop_and:	jit_andr(JIT_V1, JIT_V1, JIT_R0);	break;
		case eop_or:	jit_orr (JIT_V1, JIT_V1, JIT_R0);	break;
		default:	jit_xorr(JIT_V1, JIT_V1, JIT_R0);	break;
	    }
	    pop_stack();
	    ejit_sync = ejit_sync_register;
	    break;
	case li32|ri64|ii64:	case li64|ri32|ii64:	case li64|ri64|ii64:
	    maybe_reload_extend_ireg_implicit(ast0->rtype);
	    load_stack();
#  if __WORDSIZE == 32
	    jit_ldxi(JIT_R0, JIT_R1,
		     -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		     offsetof(edata_t, s.l));
	    jit_ldxi(JIT_R2, JIT_R1,
		     -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		     offsetof(edata_t, s.h));
	    switch (east_node(ast0)->code) {
		case eop_and:
		    jit_andr(JIT_V1, JIT_V1, JIT_R0);
		    jit_andr(JIT_V2, JIT_V2, JIT_R2);
		    break;
		case eop_or:
		    jit_orr(JIT_V1, JIT_V1, JIT_R0);
		    jit_orr(JIT_V2, JIT_V2, JIT_R2);
		    break;
		default:
		    jit_xorr(JIT_V1, JIT_V1, JIT_R0);
		    jit_xorr(JIT_V2, JIT_V2, JIT_R2);
		    break;
	    }
#  else
	    jit_ldxi(JIT_R0, JIT_R1,
		     -sizeof(evalue_t) + offsetof(evalue_t, v.i));
	    switch (east_node(ast0)->code) {
		case eop_and:	jit_andr(JIT_V1, JIT_V1, JIT_R0);	break;
		case eop_or:	jit_orr (JIT_V1, JIT_V1, JIT_R0);	break;
		default:	jit_xorr(JIT_V1, JIT_V1, JIT_R0);	break;
	    }
#  endif
	    pop_stack();
	    ejit_sync = ejit_sync_register|ejit_sync_int_ext;
	    break;
	default:
	    load_stack();
	    check = jit_forward();
	    jint = jmpz = next = null;
	    done = ast0->rtype == t_mpz ? null : jit_forward();
	    if (!(kind & (ri32|ri64|ru64))) {
		if (ast0->rtype != t_mpz) {
		    jmpz = jit_forward();
		    jit_ldxi_i(JIT_R0, JIT_V0,
			       offsetof(ethread_t, r0) + offsetof(evalue_t, t));
		    next = jit_bnei(JIT_R0, t_int);
		}
	    }
	    else
		maybe_reload_extend_ireg_implicit(ast0->rtype);
	    if (kind & ru64) {
		jmpz = jit_forward();	/* not created in above check */
#  if __WORDSIZE == 32
		jump = jit_bgei(JIT_V2, 0);
		store_ireg_implicit_rgz(RGZ_r1_to_v1, JIT_V1, JIT_V2);
#  else
		jump = jit_bgei(JIT_V1, 0);
		store_ireg_implicit_rgz(RGZ_r1_to_v1, JIT_V1);
#  endif
		/* multiple paths */
		jit_movr(JIT_R1, JIT_V1);
		temp = jit_jmpi();
		jit_patch_at(temp, jmpz);
		jit_patch(jump);
	    }
	    if (done) {
		if (!(kind & (li32|li64))) {
		    jint = jit_forward();
		    jit_ldxi_i(JIT_R0, JIT_R1,
			       -sizeof(evalue_t) + offsetof(evalue_t, t));
		    jump = jit_bnei(JIT_R0, t_int);
		    jit_patch_at(jump, jint);
		}
		/* if did not already reload due to known type */
		if (!(kind & (ri32|ri64|ru64)))
		    load_ireg_implicit();
#  if __WORDSIZE == 32
		jit_ldxi(JIT_R0, JIT_R1,
			 -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
			 offsetof(edata_t, s.l));
		jit_ldxi(JIT_R2, JIT_R1,
			 -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
			 offsetof(edata_t, s.h));
		switch (east_node(ast0)->code) {
		    case eop_and:
			jit_andr(JIT_V1, JIT_V1, JIT_R0);
			jit_andr(JIT_V2, JIT_V2, JIT_R2);
			break;
		    case eop_or:
			jit_orr(JIT_V1, JIT_V1, JIT_R0);
			jit_orr(JIT_V2, JIT_V2, JIT_R2);
			break;
		    default:
			jit_xorr(JIT_V1, JIT_V1, JIT_R0);
			jit_xorr(JIT_V2, JIT_V2, JIT_R2);
			break;
		}
#  else
		jit_ldxi(JIT_R0, JIT_R1,
			 -sizeof(evalue_t) + offsetof(evalue_t, v.i));
		switch (east_node(ast0)->code) {
		    case eop_and: jit_andr(JIT_V1, JIT_V1, JIT_R0);	break;
		    case eop_or:  jit_orr (JIT_V1, JIT_V1, JIT_R0);	break;
		    default:	  jit_xorr(JIT_V1, JIT_V1, JIT_R0);	break;
		}
#  endif
		store_ireg_implicit(!(ejit_sync & ejit_sync_implicit));
		pop_stack();
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (jint) {
		jit_link(jint);
		if (!(ejit_sync & ejit_sync_implicit))
		    store_ireg_implicit(true);
		jit_prepare(jit_call_default);
		jit_subi(JIT_V1, JIT_R1, sizeof(evalue_t));
		jit_pushargr(JIT_V1);
		switch (east_node(ast0)->code) {
		    case eop_and:	jit_finishi(evm_i_and);		break;
		    case eop_or:	jit_finishi(evm_i_or);		break;
		    default:		jit_finishi(evm_i_xor);		break;
		}
		jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
		jump = jit_jmpi();
		jit_patch_at(jump, check);
	    }
	    if (next) {
		jit_patch(next);
		jump = jit_beqi(JIT_R0, t_mpz);
		jit_patch_at(jump, jmpz);
		next = jit_bnei(JIT_R0, t_shz);
	    }
	    if (jmpz)
		jit_link(jmpz);
	    if (jmpz || ast0->rtype == t_mpz) {
		jit_prepare(jit_call_default);
		jit_subi(JIT_V1, JIT_R1, sizeof(evalue_t));
		jit_pushargr(JIT_V1);
		switch (east_node(ast0)->code) {
		    case eop_and:	jit_finishi(evm_z_and);		break;
		    case eop_or:	jit_finishi(evm_z_or);		break;
		    default:		jit_finishi(evm_z_xor);		break;
		}
		jit_stxi(offsetof(ethread_t, esp), JIT_V0, JIT_V1);
		if (next) {
		    jump = jit_jmpi();
		    jit_patch_at(jump, check);
		}
	    }
	    if (next) {
		/* this should actually cause an exception */
		jit_patch(next);
		switch (east_node(ast0)->code) {
		    case eop_and:	jit_calli(evm_and);		break;
		    case eop_or:	jit_calli(evm_or);		break;
		    default:		jit_calli(evm_xor);		break;
		}
	    }
	    jit_link(check);
	    jit_ldxi_i(JIT_R0, JIT_V0,
		       offsetof(ethread_t, r0) + offsetof(evalue_t, t));
	    jump = jit_bnei(JIT_R0, t_int);
	    load_ireg_implicit();
	    jit_patch(jump);
	    if (done)
		jit_link(done);
	    ejit_sync = ejit_sync_register|ejit_sync_implicit|
			ejit_sync_dynamic|ejit_sync_int_ext;
	    break;
    }
    ejit_type = ast0->itype;
}

static void
emit_boolean(east_list_t *ast0)
{
    jit_node_t		*done;
    jit_node_t		*next;
    jit_node_t		*jump;
    eint32_t		 kind;
    ecode_t		 code;

    code = east_node(ast0)->code;
    done = next = null;
    switch (ast0->rtype) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:	case t_uint32:
	    kind = ii32;		break;
	case t_int64:	case t_uint64:
	    kind = ii64;		break;
	case t_float32:
	    kind = if32;		break;
	case t_float:
	    kind = if64;		break;
	case t_exact:
	    kind = iint;		break;
	case t_inexact:
	    kind = irel;		break;
	case t_dynamic:
	    kind = iint|irel;		break;
	default:
	    kind = 0;			break;
    }
    switch (kind) {
	case ii32:
	    maybe_reload_ireg32_implicit();
	    if (code == eop_bool)	jit_nei(JIT_V1, JIT_V1, 0);
	    else			jit_eqi(JIT_V1, JIT_V1, 0);
	    break;
	case ii64:
	    maybe_reload_ireg_implicit();
	    if (code == eop_bool) {
		jit_nei(JIT_V1, JIT_V1, 0);
#  if __WORDSIZE == 32
		jit_nei(JIT_V2, JIT_V2, 0);
		jit_orr(JIT_V1, JIT_V1, JIT_V2);
#  endif
	    }
	    else {
		jit_eqi(JIT_V1, JIT_V1, 0);
#  if __WORDSIZE == 32
		jit_eqi(JIT_V2, JIT_V2, 0);
		jit_andr(JIT_V1, JIT_V1, JIT_V2);
#  endif
	    }
	    break;
	case if32:
	    if (!(ejit_sync & ejit_sync_register))
		load_freg_implicit();
	    else if (!(ejit_sync & ejit_sync_float_ext))
		jit_extr_f_d(JIT_F0, JIT_F1);
	    goto bool_float;
	case if64:
	    /* FIXME not yet corrected issue of using SSE instructions
	     * but generating x87 code */
	    maybe_reload_freg_implicit();
	bool_float:
	    if (code == eop_bool)	jit_nei_d(JIT_V1, JIT_F0, 0.0);
	    else			jit_eqi_d(JIT_V1, JIT_F0, 0.0);
	    break;
	default:
	    assert(ejit_sync & ejit_sync_implicit);
	    if (kind) {
		done = jit_forward();
		jit_ldxi_i(JIT_R0, JIT_V0,
			   offsetof(ethread_t, r0) + offsetof(evalue_t, t));
	    }
	    if (kind & iint) {
		next = jit_bnei(JIT_R0, t_int);
		maybe_reload_ireg_implicit();
		if (code == eop_bool) {
		    jit_nei(JIT_V1, JIT_V1, 0);
#  if __WORDSIZE == 32
		    jit_nei(JIT_V2, JIT_V2, 0);
		    jit_orr(JIT_V1, JIT_V1, JIT_V2);
#  endif
		}
		else {
		    jit_eqi(JIT_V1, JIT_V1, 0);
#  if __WORDSIZE == 32
		    jit_eqi(JIT_V2, JIT_V2, 0);
		    jit_andr(JIT_V1, JIT_V1, JIT_V2);
#  endif
		}
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (kind & irel) {
		if (next)
		    jit_patch(next);
		next = jit_bnei(JIT_R0, t_float);
		maybe_reload_freg_implicit();
		if (code == eop_bool)	jit_nei_d(JIT_V1, JIT_F0, 0.0);
		else			jit_eqi_d(JIT_V1, JIT_F0, 0.0);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
		/* FIXME check mpfr and null */
	    }
	    if (next)
		jit_patch(next);
	    DEBUG_IMPLICIT_TYPE();
	    if (code == eop_bool)	jit_calli(evm_bool);
	    else			jit_calli(evm_not);
	    load_ireg32_implicit();
	    if (done)
		jit_link(done);
	    break;
    }
    ejit_sync = ejit_sync_register;
    ejit_type = ast0->itype;
}

static void
emit_load_jmp(east_list_t *ast0, east_list_t *ast1)
{
    jit_node_t		*done;
    jit_node_t		*jump;
    jit_node_t		*next;
    jit_node_t		*none;
    jit_node_t		*lmpr;
    jit_node_t		*lrgr;
    ebool_t		 cond;
    eint32_t		 kind;
    ecode_t		 load;
    eint32_t		 soff;
    eint32_t		 toff;
    eint32_t		 voff;
    ebool_t		 used;
    etype_t		 type;
    eword_t		 index;
    elabel_t		*label;

    used = !!(east_node(ast1)->csimple.flags & code_flags_implicit);
    cond = east_node(ast1)->code != eop_jf;
    label = east_node(ast1)->clabel.label;
    if (label->value == null)
	allocate_forward_label(label);
    index = eget_fixnum(label->value);
    if (ast0) {
	load = east_node(ast0)->code;
	kind = type = ast0->itype;
	soff = east_node(ast0)->csymbol.symbol->offset;
    }
    else {
	soff = 0;
	load = eop_noop;
	kind = type = ast1->rtype;
	voff = offsetof(ethread_t, r0) + offsetof(evalue_t, v.o);
    }
    switch (kind) {
	case t_int8:	case t_uint8:	case t_int16:	case t_uint16:
	case t_int32:	case t_uint32:
	    kind = ii32;		break;
	case t_int64:	case t_uint64:
	    kind = ii64;		break;
	case t_float32:
	    kind = if32;		break;
	case t_float:
	    kind = if64;		break;
	case t_exact:
	    kind = iint;		break;
	case t_inexact:
	    kind = irel;		break;
	case t_dynamic:
	    kind = iint|irel;		break;
	default:
	    kind = 0;			break;
    }
    switch (load) {
	case eop_noop:
	    toff = offsetof(ethread_t, r0) + offsetof(evalue_t, t);
	    voff = offsetof(ethread_t, r0) + offsetof(evalue_t, v.o);
	    break;
	case eop_ld:	case eop_ldt:
	    if (kind) {
		jit_ldi(JIT_R1, (jit_word_t)
			(eint8_t *)eds + soff * sizeof(eobject_t));
		toff = -4;
		voff = 0;
	    }
	    break;
	case eop_lb:	case eop_lbt:
	    if (kind) {
		jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
		toff = soff * sizeof(evalue_t) + offsetof(evalue_t, t);
		voff = soff * sizeof(evalue_t) + offsetof(evalue_t, v.o);
	    }
	    break;
	case eop_lc:
	    if (kind) {
		jit_ldxi(JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
		/* pointer to 'this' */
		jit_ldxi(JIT_R1, JIT_R1,
			 -2 * sizeof(evalue_t) + offsetof(evalue_t, v.o));
		toff = -4;
		voff = soff;
	    }
	    break;
	default:
	    abort();
    }
    switch (kind) {
	case ii32:
	    switch (load) {
		case eop_noop:
		    maybe_reload_ireg32_implicit();
		    if (used && !(ejit_sync & ejit_sync_implicit)) {
			zero_sign_extend(type);
			store_ireg_implicit(true);
		    }
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg_type(JIT_R1, voff, type);
		    load_ireg(JIT_R1, voff);
		    if (used) {
			zero_sign_extend(type);
			store_ireg_implicit(true);
		    }
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(JIT_R1, voff, type);
		    if (used) {
			zero_sign_extend(type);
			store_ireg_implicit(true);
		    }
		    break;
		default:
		    abort();
	    }
	    jump = cond ? jit_bnei(JIT_V1, 0) : jit_beqi(JIT_V1, 0);
	patch:
	    if (index >= 0)	jit_patch_at(jump, labels[index]);
	    else		record_forward_patch(jump, -index);
	    break;
	case ii64:
	    switch (load) {
		case eop_noop:
		    maybe_reload_ireg_implicit();
		    if (used && !(ejit_sync & ejit_sync_implicit))
			store_ireg_implicit(true);
		    break;
		case eop_ld:	case eop_lb:
		    load_ireg(JIT_R1, voff);
		    if (used)
			store_ireg_implicit(true);
		    break;
		case eop_ldt:	case eop_lbt:	case eop_lc:
		    load_ireg_type(JIT_R1, voff, type);
		    if (used)
			store_ireg_implicit(true);
		    break;
		default:
		    abort();
	    }
#  if __WORDSIZE == 32
	    jit_nei(JIT_R0, JIT_V1, 0);
	    jit_nei(JIT_R2, JIT_V2, 0);
	    jit_orr(JIT_R0, JIT_R0, JIT_R2);
	    jump = cond ? jit_bnei(JIT_R0, 0) : jit_beqi(JIT_R0, 0);
#  else
	    jump = cond ? jit_bnei(JIT_V1, 0) : jit_beqi(JIT_V1, 0);
#  endif
	    goto patch;
	case if32:
	    if (load == eop_noop) {
		if (!(ejit_sync & ejit_sync_register))
		    load_freg_implicit();
		else if (!(ejit_sync_float_ext))
		    jit_extr_f_d(JIT_F0, JIT_F1);
	    }
	    else {
		load_freg_type(JIT_R1, voff, t_float32);
		jit_extr_f_d(JIT_F0, JIT_F1);
	    }
	    goto float_jmp;
	case if64:
	    if (load == eop_noop)
		maybe_reload_freg_implicit();
	    else
		load_freg(JIT_R1, voff);
	float_jmp:
	    if (used &&	(load != eop_noop || !(ejit_sync & ejit_sync_implicit)))
		store_freg_implicit(true);
	    jump = cond ? jit_bnei_d(JIT_F0, 0.0) : jit_beqi_d(JIT_F0, 0.0);
	    goto patch;
	default:
	    done = next = none = null;
	    if (kind) {
		done = jit_forward();
		switch (load) {
		    case eop_noop:
			assert(ejit_sync & ejit_sync_implicit);
			jit_ldxi_i(JIT_R0, JIT_V0, toff);
			break;
		    case eop_lb:
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			break;
		    case eop_ld:
			none = jit_beqi(JIT_R1, 0);
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			break;
		    case eop_lc:
			jit_ldxi(JIT_R1, JIT_R1, voff);
			none = jit_beqi(JIT_R1, 0);
			jit_ldxi_i(JIT_R0, JIT_R1, toff);
			voff = 0;
			break;
		    default:
			abort();
		}
	    }
	    if (kind & iint) {
		next = jit_bnei(JIT_R0, t_int);
		if (load == eop_noop)
		    maybe_reload_ireg_implicit();
		else {
		    load_ireg(JIT_R1, voff);
		    if (used)
			store_ireg_implicit(true);
		}
#  if __WORDSIZE == 32
		jit_nei(JIT_R0, JIT_V1, 0);
		jit_nei(JIT_R2, JIT_V2, 0);
		jit_orr(JIT_R0, JIT_R0, JIT_R2);
		jump = cond ? jit_bnei(JIT_R0, 0) : jit_beqi(JIT_R0, 0);
#  else
		jump = cond ? jit_bnei(JIT_V1, 0) : jit_beqi(JIT_V1, 0);
#  endif
		if (index >= 0)	jit_patch_at(jump, labels[index]);
		else		record_forward_patch(jump, -index);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (kind & irel) {
		/* check float */
		if (next)
		    jit_patch(next);
		next = jit_bnei(JIT_R0, t_float);
		if (load == eop_noop)
		    maybe_reload_freg_implicit();
		else {
		    load_freg(JIT_R1, voff);
		    if (used)
			store_freg_implicit(true);
		}
		jump = cond ?
		       jit_bnei_d(JIT_F0, 0.0) : jit_beqi_d(JIT_F0, 0.0);
		if (index >= 0)	jit_patch_at(jump, labels[index]);
		else		record_forward_patch(jump, -index);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
		/* check mpfr */
		jit_patch(next);
		lmpr = jit_beqi(JIT_R0, t_mpr);
		if (load == eop_noop)	lrgr = jit_beqi(JIT_R0, t_rgr);
		next = jit_bnei(JIT_R0, t_shr);
		jit_patch(lmpr);
		if (load == eop_noop)	jit_patch(lrgr);
		jit_prepare(jit_call_default);
		if (load == eop_noop)
		    jit_ldxi(JIT_R2, JIT_V0, voff);
		else {
		    jit_ldxi(JIT_R2, JIT_R1, voff);
		    if (used) {
			jit_stxi(offsetof(ethread_t, r0) +
				 offsetof(evalue_t, v.o), JIT_V0, JIT_R2);
			jit_stxi_i(offsetof(ethread_t, r0) +
				   offsetof(evalue_t, t), JIT_V0, JIT_R0);
		    }
		}
		jit_pushargr(JIT_R2);
		jit_finishi(mpfr_zero_p);
		jit_retval_i(JIT_R0);
		jump = cond ? jit_beqi(JIT_R0, 0) : jit_bnei(JIT_R0, 0);
		if (index >= 0)	jit_patch_at(jump, labels[index]);
		else		record_forward_patch(jump, -index);
		jump = jit_jmpi();
		jit_patch_at(jump, done);
	    }
	    if (kind) {
		/* check null */
		if (next)
		    jit_patch(next);
		next = jit_bnei(JIT_R0, t_void);
		if (used) {
		    jit_stxi_i(offsetof(ethread_t, r0) + offsetof(evalue_t, t),
			       JIT_V0, JIT_R0);
		    jit_stxi(offsetof(ethread_t, r0) + offsetof(evalue_t, v.o),
			     JIT_V0, JIT_R0);
		}
		jump = jit_jmpi();
		if (cond)
		    jit_patch_at(jump, done);
		else {
		    if (index >= 0)	jit_patch_at(jump, labels[index]);
		    else		record_forward_patch(jump, -index);
		}
	    }
	    if (none) {
		if (used) {
		    jit_patch(none);
		    jit_stxi_i(offsetof(ethread_t, r0) + offsetof(evalue_t, t),
			       JIT_V0, JIT_R1);
		    jit_stxi(offsetof(ethread_t, r0) + offsetof(evalue_t, v.o),
			     JIT_V0, JIT_R1);
		    jump = jit_jmpi();
		}
		else
		    jump = none;
		if (cond)
		    jit_patch_at(jump, done);
		else {
		    if (index >= 0)	jit_patch_at(jump, labels[index]);
		    else		record_forward_patch(jump, -index);
		}
	    }
	    if (next)
		jit_patch(next);
	    if (used) {
		switch (load) {
		    case eop_noop:					break;
		    case eop_ld:	call_vi(evm_ld, soff);		break;
		    case eop_lb:	call_vi(evm_lb, soff);		break;
		    case eop_lc:	call_vii(evm_lc, soff, type);	break;
		    default:		abort();
		}
		DEBUG_IMPLICIT_TYPE_NULL_MPR();
	    }
	    /* possible false values already tested */
	    if (cond) {
		jump = jit_jmpi();
		if (index >= 0)		jit_patch_at(jump, labels[index]);
		else			record_forward_patch(jump, -index);
	    }
	    if (done)
		jit_link(done);
	    break;
    }
    if (used) {
	ejit_sync = ejit_sync_register|ejit_sync_implicit|
		    ejit_sync_dynamic|ejit_sync_int_ext;
	ejit_type = ast1->rtype;
    }
    else
	emit_clear();
}
#endif
